GithubHelp home page GithubHelp logo

nodesolidserver / solid-auth-client Goto Github PK

View Code? Open in Web Editor NEW
95.0 27.0 42.0 8.27 MB

A browser library for performing authenticated requests to Solid pods

Home Page: https://solid.github.io/solid-auth-client/

License: MIT License

JavaScript 96.93% CSS 1.45% Shell 1.28% EJS 0.34%
running-code

solid-auth-client's Introduction

A library for reading and writing to legacy Solid pods

Build Status Coverage Status NPM Package

The Solid project allows people to use apps on the Web while storing their data in their own data pod.

solid-auth-client is a legacy browser library that allows your apps to log in and read/write data using a Node Solid Server.

⚠️ New projects should use solid-client-authn or solid-auth-fetcher instead, which leverage the secure DPoP authentication mechanism from the current Solid specification, as implemented by all the various Solid server implementations.

Usage

In the browser, the library is accessible through solid.auth:

<script src="https://solid.github.io/solid-auth-client/dist/solid-auth-client.bundle.js"></script>
<script>
solid.auth.trackSession(session => {
  if (!session)
    console.log('The user is not logged in')
  else
    console.log(`The user is ${session.webId}`)
})
</script>

When developing for webpack in a Node.js environment, run npm install solid-auth-client and then do:

const auth = require('solid-auth-client')

auth.trackSession(session => {
  if (!session)
    console.log('The user is not logged in')
  else
    console.log(`The user is ${session.webId}`)
})

Note that this library is intended for the browser. You can use Node.js as a development environment, but not for actually logging in and out or making requests.

Functionality

This library offers two main types of functionality:

  • fetch functionality to make authenticated HTTP requests to a Solid pod
  • login and logout functionality to authenticate the user

Reading and writing data

The fetch method mimics the browser's fetch API: it has the same signature and also returns a promise that resolves to the response to the request. You can use it to access any kind of HTTP(S) document, regardless of whether that document is on a Solid pod:

solid.auth.fetch('https://timbl.com/timbl/Public/friends.ttl')
  .then(console.log);
const { fetch } = solid.auth;
fetch('https://timbl.com/timbl/Public/friends.ttl')
  .then(console.log);

If the document is on a Solid pod, and the user is logged in, they will be able to access private documents that require read or write permissions.

Logging in

Since Solid is decentralized, users can have an account on any server. Therefore, users need to pick their identity provider (IDP) in order to log in.

If your application asks them for the URL of their identity provider, then you can call the login method with the IDP as an argument:

async function login(idp) {
  const session = await solid.auth.currentSession();
  if (!session)
    await solid.auth.login(idp);
  else
    alert(`Logged in as ${session.webId}`);
}
login('https://solidcommunity.net');

Be aware that this will redirect the user away from your application to their identity provider. When they return, currentSession() will return their login information.

If you want solid-auth-client to ask the user for their identity provider, then you can use a popup window:

async function popupLogin() {
  let session = await solid.auth.currentSession();
  let popupUri = 'https://solidcommunity.net/common/popup.html';
  if (!session)
    session = await solid.auth.popupLogin({ popupUri });
  alert(`Logged in as ${session.webId}`);
}
popupLogin();

The popup has the additional benefit that users are not redirected away.

You can find a popup in dist-popup/popup.html.

Logging out

To log out, simply call the logout method:

solid.auth.logout()
  .then(() => alert('Goodbye!'));

Getting the current user

The current user is available through the currentSession method. This returns a session, with the webId field indicating the user's WebID.

async function greetUser() {
  const session = await solid.auth.currentSession();
  if (!session)
    alert('Hello stranger!');
  else
    alert(`Hello ${session.webId}!`);
}
greetUser();

If you want to track user login and logout, use the trackSession method instead. It will invoke the callback with the current session, and notify you of any changes to the login status.

solid.auth.trackSession(session => {
  if (!session)
    alert('Hello stranger!');
  else
    alert(`Hello ${session.webId}!`);
});

Events

SolidAuthClient implements EventEmitter and emits the following events:

  • login (session: Session) when a user logs in
  • logout () when a user logs out
  • session (session: Session | null) when a user logs in or out

Client registration

SolidAuthClient automatically registers your OIDC client application if it is unknown to the authorization server, following the registration request spec.

You can specify some fields of this registration request by passing them to the loginSession parameter of solid.auth.login.

Supported fields are:

  • client_name and internationalized variants (clientName property)
  • contacts (contacts property)
  • logo_uri (logoUri property)

Example:

solid.auth.login(idp, {
    clientName: 'My Example',
    'clientName#ja-Jpan-JP': 'クライアント名',
    logoUri: 'https://client.example.org/logo.png',
    contacts: ['[email protected]', '[email protected]']
})

Advanced usage

Generating a popup window

To log in with a popup window, you'll need a popup application running on a trusted domain which authenticates the user, handles redirects, and messages the authenticated session back to your application.

In order to tell the user they're logging into your app, you'll need to generate a static popup bound to your application's name.

  1. Make sure you've got the solid-auth-client package installed globally.
$ npm install -g solid-auth-client # [--save | --save-dev]
  1. Run the generation script to generate the popup's HTML file.
$ solid-auth-client generate-popup # ["My App Name"] [my-app-popup.html]
  1. Place the popup file on your server (say at https://localhost:8080/popup.html).

  2. From within your own app, call solid.auth.popupLogin({ popupUri: 'https://localhost:8080/popup.html' }).

Developing solid-auth-client

Developing this library requires Node.js >= v10.0.

Setting up the development environment

$ git clone https://github.com/solid/solid-auth-client.git
$ cd solid-auth-client
$ npm install
$ npm run test     # run the code formatter, linter, and test suite
$ npm run test:dev # just run the tests in watch mode

Demo app

You can test how solid-auth-client operates within an app by running the demo app.

Running the demo development server

$ POPUP_URI='http://localhost:8606/popup-template.html' npm run start:demo

Running the popup development server

$ APP_NAME='solid-auth-client demo' npm run start:popup

solid-auth-client's People

Contributors

bourgeoa avatar christophehenry avatar dan-f avatar dmitrizagidulin avatar elf-pavlik avatar jaxoncreed avatar jeff-zucker avatar jordanshurmer avatar michielbdejong avatar mitzi-laszlo avatar noeldemartin avatar otto-aa avatar pheyvaer avatar rubensworks avatar rubenverborgh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solid-auth-client's Issues

Opening popup without caller leads to TypeError

Just opening the generated popup HTML in the browser leads to Uncaught (in promise) TypeError: Cannot read property 'postMessage' of null. I think we had a more helpful error message in the past.

Consider using devDependencies

A lot of the current dependencies are actually devDependencies, so they are unnecessarily installed when using npm install solid-auth-client.

Ensure currentSession is valid and not expired

The session returned by currentSession may or may no longer be valid. In the latter case web requests will return 401. It would be handy to have a session.isValid() function that returns true if the session is still valid and false otherwise.

FR: typescript defs

Hello, just wondering if there is a future with typescript definitions for solid-auth-client. Thanks!

Issue with Login operation

The issue I am currently facing is I am unable to log in, I get an CORS error in my browser console.

I am using solid-auth-client bundle available here: https://github.com/solid/solid-auth-client/tree/gh-pages/dist . It has been added using rawgit.com CDN.

The snippet to javascript of my login operation is here,

// Logs in user into the Solid Pod
async function login(idp) {
  const session=await solid.auth.currentSession();
  // throws error in console
  if(!session) await solid.auth.login(idp);
  else{
    // hides the form
  idpForm.style.display="none";
   // displays logout button
  logoutButton.style.display="inline-block";
  }
}

The behavior of solid-auth-client has changed from few hours, it now re-directs to an IDP login page instead of logging me in. Earlier when using the snippet provided in docs, it would directly log me in without an redirections.

The problem is, this snippet is producing a CORS error instead of redirection.

You can view my full code here: https://github.com/pavittarx/solid-minimal
Just the Javascript file: https://github.com/pavittarx/solid-minimal/blob/master/assests/js/script.js


Errors being produced:

Failed to load https://stripe.community/.well-known/openid-configuration: Redirect from 'https://stripe.community/.well-known/openid-configuration' to 'https://discuss.stripe.community/.well-known/openid-configuration' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9227' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

image

bodyUsed consistently false

Hi,

on fetches of text/plain MIME type the bodyUsed stays false

        solid.auth.fetch('https://roger.localhost:8443/public/scad/primary-disk.scad', {
           method: 'GET',
           headers:{
	    'Accept': 'Authorization, Origin, text/*'
	   }
        }).then((result)=>{
          if(result.bodyUsed){
            result.text().then((t)=>{callback(null, t);}).catch((e) => {console.error('Error:', JSON.stringify(e));});
          }
          else {
            callback("No body for "+path, null);
          }
        }).catch((error) => {console.error('Error:', error);});

I'm using today's clones of this project and node-solid-server. Using curl The content I pushed in with this project is returned

curl -k --cert ../roger-g74s.cert --key ../roger-g74s.key -I https://roger.localhost:8443/public/scad/primary-disk.scad

Is there anything that needs to be set? Any header? The same result with

solid.auth.fetch('https://roger.localhost:8443/public/scad/primary-disk.scad')
  .then(console.log);

bodyUsed is false and get header stuff and ok is true status 200

Unauthorized to access my pod even when connected

I'm using the solid-auth-client on my server hosting webcomponents, and i'm trying to access a container on my pod.
The login is successful, the session variable is filled, but the fetch function doesn't seem to know i'm connected, as solid throws me a 401 Unauthorised.

Is there a fetch function on session ? Because session.fetch is undefined for me.

By the way doing the same thing with OIDCWebClient works for me

Authentication in 2 different tabs with 2 different sets of credentials confuses rights.

This issue happens on instances of node-solid-server with firefox (i.e. https://solid.community, https://solidtest.space)

Preparation

  1. Have 2 different solid accounts/WebIDs (user0, user1)
  2. Create a new chat in https://user0.somehost/public/chat (chat)
  3. Add user1 to Posters (i.e. give her Append rights). User0 should already be Owner of the chat. Now, both user0 and user1 should be able to add new messages, but only user0 should be able to delete messages.
  4. Clear cookies or whatever place the credentials are stored.

Issue

  1. Open a new tab with the chat and log in as user0.
  2. Open another tab with the chat (you should see Log In button) and log in as user1.
  3. Now user1 is able to both post messages as user1 and delete messages.

Expected behaviour

One of the following:

  • Allow only 1 logged user (i.e. be already logged in) when opening a new tab with a solid app.
  • Use a consistent authentication for every tab.

Hypothesis

Authentication seems to be done with a cookie, and in both cases the same cookie seems to be used; with the rights of the first logged in user.

Browser: firefox 60.0
Operating system: Arch Linux

Reduce library size

The minified file is currently 116KB. I wonder if we could do something about it.

With source-map-explorer, I obtained this diagram. I wonder if there are some components we can drop, such as Validator.js and buffer.

Error: Cannot issue PoPToken - missing session key

alert:

"You don't have, or you couldn't acess, type indexes --lists of things of different types. Create new empty ones? Error: [LTI] Error: (via loadPrefs) Logged in but cannot load profile https://www.w3.org/People/Berners-Lee/card : Error: Fetcher: fetch failed: Error: Cannot issue PoPToken - missing session key

(Logged in as https://www.w3.org/People/Berners-Lee/card#i by authentication)
mashlib.js:20158 logIn: Already logged in as https://www.w3.org/People/Berners-Lee/card#i
mashlib.js:51169 Fetcher: https://www.w3.org/People/Berners-Lee/card Non-HTTP fetch error: Error: Cannot issue PoPToken - missing session key

Maintain multiple configurations in localStorage

Currently, localStorage can only contain one RP configuration, but this configuration is specific to the IDP and the redirect URI. If any of these are different, a new RP is created (which was introduced to fix #54). This potentially creates a lot of RP entries on the server.

No support for Microsoft Edge

There needs to be some kind of check to make sure that features, such as TextEncoder, are available before use and if not then provide an alternative.

Many work places are still limited to Microsoft only browsers and it would be useful if this could work from those.

I realise that Internet Explorer is probably not a valid target (Especially as Windows 7 will be out of support soon) and there would have to be a lot of custom implementation to sort this, but I don't think supporting Edge should be outside of scope

Allow authenticated fetch in a Web Worker

Many Web applications perform tasks in a Web Worker, and this includes fetching.
Therefore, it would be useful if this library's fetch would also function in a Web Worker.

Of course, the library cannot fully do everything in the Web Worker (since logging in involves redirecting etc.), but if the fetch functionality could be transferable to worker, that would be great. One option for this is that the required settings can be serialized as a JSON object in the main window, and then be reconstructed in the worker.

Preserve original redirect_uri hash fragment when parsing authentication response

Refactor browser-util.js / clearHashFragment() to preserve the original hash fragment while clearing out oidc-related hash fragment parameters.

For example, user requests the page https://example.com/resource#someHashFragment, and initiates a WebID-OIDC login flow.
The client will send redirect_uri=https://example.com/resource#someHashFragment as part of its implicit authorization flow. On the return step, the user's browser will be redirected back to the redirect_uri with additional credentials and auth-related parameters. It will be 302 redirected to:
https://example.com/resource#someHashFragment&id_token=...&state=... etc.

In currentSession(), when parsing the response and clearing the hash fragment of the uri, only the following hash fragment params need to be cleared out (see OIDC ImplicitAuthResponse):

  • id_token
  • access_token
  • state
  • token_type
  • expires_in

So that the resulting cleared uri should be https://example.com/resource#someHashFragment.

(Affects downstream issue nodeSolidServer/node-solid-server#571)

Cannot find module "algorithms/RSASSA-PKCS1-v1_5"

I'm developing an Angular6+ solid-app (codebase). The app itself depends on:

"crypto-js": "^3.1.9-1",
"rdflib": "^0.19.0",
"solid-auth-client": "^2.2.6",
"stream": "0.0.2",
"webcrypto": "^0.1.1",
"zone.js": "^0.8.26"

What I'm trying to do is deleting a RDF resource using rdflib.UpdateManager.update():

    $rdf.UpdateManager(this.store).update(toBeDeleted, [], (uri, ok, message, response) => {
      if (ok) {
        console.log('DELETED')
      } else {
        console.warn(message)
      }
    })

You can find more the JSDoc about the UpdateManager here and an introduction of rdflib.js here.

Now, using Firefox 63.0b12 (64-bit), I keep getting the following error which I think could be related to the fact that accessing to the WebCrypto API should be restricted to secure origins (which is to say https:// pages). The same error is fired when using Opera.

Unhandled Promise rejection: Cannot find module "../algorithms/RSASSA-PKCS1-v1_5". ; Zone: <root> ; Task: Promise.then ; Value: Error: Cannot find module "../algorithms/RSASSA-PKCS1-v1_5".
at webpackEmptyContext (algorithms sync:2)
at SupportedAlgorithms.normalize (SupportedAlgorithms.js:84)
at SubtleCrypto.importKey (SubtleCrypto.js:279)
at RSASSA_PKCS1_v1_5.importKey (RSASSA-PKCS1-v1_5.js:124)
at Function.importKey (JWA.js:113)
at Function.importKey (JWK.js:46)
at Function.issueFor (PoPToken.js:57)
at webid-oidc.js:183
at fetchWithCredentials (authn-fetch.js:63)
at authn-fetch.js:41 Error: Cannot find module "../algorithms/RSASSA-PKCS1-v1_5".
at webpackEmptyContext (http://localhost:4200/main.js:11:10)
at SupportedAlgorithms.normalize (http://localhost:4200/vendor.js:132732:107)
at SubtleCrypto.importKey (http://localhost:4200/vendor.js:132336:51)
at RSASSA_PKCS1_v1_5.importKey (http://localhost:4200/vendor.js:124747:28)
at Function.importKey (http://localhost:4200/vendor.js:125342:34)
at Function.importKey (http://localhost:4200/vendor.js:125411:18)
at Function.issueFor (http://localhost:4200/vendor.js:127189:18)
at http://localhost:4200/vendor.js:185374:44
at fetchWithCredentials (http://localhost:4200/vendor.js:184423:49)
at http://localhost:4200/vendor.js:184401:16

I've traced back the issue using the debugger ending up at webid-oidc.js:183, and there I stopped because I didn't see anything clearly wrong.

Am I missing a npm dependency? What is the root cause of this issue?

Unable to import solid-auth-client

When attempting to import solid-auth-client (tried many different ways, most recently "import * as solid from 'solid-auth-client'") it is undefined.

I've been unable to import it into any apps using the es6 style notation. Instead, I've resorted to including the script manually and adding declare let solid; into pages or classes that need to use it.

For applications that aren't using webpack and don't have commonJS, please fix importing so we don't need a workaround.

Add login and logout events

That way, components can just listen in order to update their state.

Right now, they have no way of knowing when another components started a login.

Logging in after logging out breaks fetch

When I perform the following steps:

  1. SolidAuthClient.login("https://solidtest.space/") (and log in with with username / password)
  2. SolidAuthClient.fetch("https://my.solidtest.space/private-resource")
  3. SolidAuthClient.logout()
  4. SolidAuthClient.login("https://solidtest.space/")
  5. SolidAuthClient.fetch("https://my.solidtest.space/private-resource")

Here, we assume https://my.solidtest.space/private-resource triggers a 401.

The following happens:

  • In step 2, a 401 is followed by another GET, resulting in 200 (as expected)
  • In step 4, I am not redirected to log in, but rather logged in automatically (not fully expected).
  • In step 5, the 401 is not followed by another GET

This occurs because, after step 2, solidtest.space sets a cookie which automatically authenticates me in step 4, but does not set an access token.

Sync version of currentUser()

Hmmm … Looking at a lot of places where me = tabulator.preferemces.get(‘me’) is replaced by me = UI.authn.currentUser() but that last is async, returns a promise. It sems a shame that it has to return a promise — after all it should not do any net access etc
Can we make it sync, or make a sync version?

It should be a quick check and not take any time, so sync should be fine.

The version below I pit in solid-ui/sigin.js note does not check for expiry of creds

Dmitri Zagidulin @dmitrizagidulin 20:42
i'll take a look. do you mind opening an issue?

Tim Berners-Lee @timbl 20:43
I have made a local one for now

/** Checks syncronously whether user is logged in
 *
 * @returns Named Node or null
*/
function currentUser () {
  let str = localStorage['solid-auth-client']
  if (str) {
    let da = JSON.parse(str)
    if (da.session && da.session.webId) {
      // @@ check has not expired
      return $rdf.sym(da.session.webId)
    }
  }
  return null
  // JSON.parse(localStorage['solid-auth-client']).session.webId
}

Add write example to README (for example PUT)

There is a section on the README called reading and writing data. However it only shows how to read, and not write. I think it would be helpful to add an example to write data with an HTTP PUT.

Reading and writing data

The fetch method mimics
the browser's fetch API.
You can use it to access any kind of HTTP(S) document,
regardless of whether that document is on a Solid pod:

solid.auth.fetch('https://timbl.com/timbl/Public/friends.ttl')
  .then(console.log);
const { fetch } = solid.auth;
fetch('https://timbl.com/timbl/Public/friends.ttl')
  .then(console.log);

If the document is on a Solid pod,
and the user is logged in,
they will be able to access private documents
that require read or write permissions.

https://github.com/solid/solid-auth-client#reading-and-writing-data

Solid-auth-client mistakenly thinks cross-domain auth with WebID is possible

It is impossible to log in with a WebID on domain A and then "transfer" that authentication to domain B (without using OIDC). However, solid-auth-client seems to think it is, mistakenly indicating "logged in" on the client side, but this login is not reflected on the server (because that is not possible).

Double firing of login event

When logging in with .login() in the browser, I noticed that the login event is firing twice.

We should fix the cause, but perhaps also ensure that login and logout events can only fire on actual status changes.

Redirection on register only redirects me to solid server

On my app I use the .login from OIDCWebClient or solid-auth-client (tried with both)
Then I click on "register" and on success, I expected to be redirected back on my app, but instead I get redirected on the Databrowser on the solid Server.

How can I be redirected back to my app on register success ?

Implement Select Provider popup window capability

If the app developer doesn't provide their own 'select provider' UI, it would be helpful if calling login() without passing in an IDP would open a Select Provider popup.

There's two workflow options for this popup window that we have to decide between -- either 1) it serves as a select provider UI only, and it's the main app window that redirects for the OAuth dance. Or 2) The redirect happens in the popup window, which is more convenient for the app developer, but involves more moving parts to implement.

Recommendation: We can start with implementing Option 1, since that's the easiest, and discuss the next steps.

Option 1 - Popup is Select Provider Only, Main App Window Redirects

pro: Implementing this requires less moving parts.

con: More inconvenient for the app developer; the user can potentially lose their place in the page after the resulting redirect (for some single-page js apps, like Tabulator).

Workflow:

  1. main window: login() is called with no IDP, popup window is opened, shows a list of IDPs (plus at least a textbox for user to enter their own domain or webid or preferred provider).
  2. popup: User clicks on a provider (or enters a url in the textbox), popup window sends a postMessage() event to the opener (main app window) with the url of the selected provider and closes itself.
  3. main window: Main window (the auth client) receives the providerSelected event, loads the RP client config for that IDP, constructs the /authorize URL, and redirects itself to login.
  4. main window: User logs in. When the IDP redirects the user to the post-login redirect_uri (usually the same URI as the main app was), the app logic calls authClient.currentSession() on page load, which results in the auth client parsing the callback uri and extracting the credentials from it, as usual.

Sample code snippets:

var selectProviderWindow
// providerSelectPopupSource is a string that contains the HTML + JS of the popup window

initEventListeners()

if (selectProviderWindow) {
  // Popup has already been opened
  selectProviderWindow.focus()
} else {
  // Open a new Provider Select popup window
  selectProviderWindow = window.open('',
    'selectProviderWindow',
    'menubar=no,resizable=yes,width=400,height=400'
  )

  selectProviderWindow.document.write(providerSelectPopupSource)
  selectProviderWindow.document.close()  // important
}

function initEventListeners() {
  window.addEventListener('message', function (event) {
    switch (event.data.event_type) {
      case 'providerSelected':
        dispatchProviderSelected(event.data.value)  // provider uri

        break
      default:
        console.error('unknown event type: ', event)

        break
  })
}

In the popup window:

// opener is a browser global
function selectProvider (providerUri) {
  console.log('Provider selected: ', providerUri)
  
  var message = {
    event_type: 'providerSelected',
    value: providerUri
  }

  opener.postMessage(message, opener.window.location.origin)
  // close yourself
  window.close()
}

Option 2 - Popup is Select Provider + Redirect to Login, Main Window Not Redirected

pro: More convenient for the app developer (user's place / workflow in the main app page is not interrupted).

con: More moving parts to implement (would require alteration to solid-server & config).

Workflow:

  1. main window: Decide on the callback redirect_uri during RP dynamic registration (see the callback uri discussion below).
  2. main window: login() is called with no IDP, popup window is opened, shows a list of IDPs (plus at least a textbox for user to enter their own domain or webid or preferred provider).
  3. popup: User clicks on a provider (or enters a url in the textbox), popup window sends a postMessage() event to the opener (main app window) with the url of the selected provider, and stays open.
  4. main window: Main window (the auth client) receives the providerSelected event, loads the RP client config for that IDP, constructs the /authorize URL, and redirects the popup window to login.
  5. popup: User logs in. When the IDP redirects the popup to the post-login redirect_uri, some logic in the redirect_uri page must do a postMessage to the opener (main app page) with its own uri (containing hash fragments with credentials), and closes itself. (See the discussion below).
  6. main window: Receives the authCallback event from the popup window, with the callback uri as the event payload. Extracts the credentials from that uri, as usual (instead of currentSession deriving them from the main page's own current uri).

The tricky bit is step 5. What should be the redirect_uri that the RP client pre-registers, and asks to be redirected to during the authentication workflow? There's basically 3 options:

  1. The rp client uses its own URI as a redirect_uri (like it currently does). In order for this to work, though, the main app code needs to have a snippet like:

    // in the 'onload' window event
    if (opener) {
      opener.postMessage({ event_type: 'authCallback', value: window.location.href }, opener.window.location.origin)
      window.close()  // close yourself
    }

    as soon as the page loads (so that the full app doesn't load in the popup window).

  2. The app developer includes a callback.html (see below) as part of their web application, and tells the RP to register it as the redirect_uri.

  3. We include a callback.html in the /common/ folder of all node-solid-server installations, and advertise the callback_uri endpoint either via a Link rel header, or via a service config document. The RP discovers this uri, and includes it in the redirect_uris list during dynamic registration.

Sample callback.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-type" content="text/html;charset=utf-8">
  <script type="text/javascript">
    window.addEventListener('load', function () {
      var callbackUrl = window.location.href
      var opener = window.opener
      var pageOrigin = opener.location.origin

      var message = {
        event_type: 'authCallback',
        value: callbackUrl
      }

      opener.postMessage(message, pageOrigin)
      window.close()
    })
  </script>
</head>
<body>
<h1>Login successful</h1>

<p>Please close this window.</p>
</body>
</html>

Can I force authentication?

Now, the library always first needs to encounter 401, creating double the number of requests.
What is the reason for not always sending auth headers when I use the library's fetch method?

Can I force sending the auth headers, for instance through options?

Error: expected postMessage call for 'storage/getItem' to return a string, but got value null

When opening the popup in Chrome from an http: host, the following bug can occur:

popup.html:10 Error: expected postMessage call for 'storage/getItem' to return a string, but got value null
    at popup.html:10
    at _ (popup.html:24)
    at Generator._invoke (popup.html:24)
    at Generator.e.(anonymous function) [as next] (http://lab1.websys/profile-viewer-tutorial/popup.html:24:67449)
    at o (popup.html:10)
    at popup.html:10
(anonymous) @ popup.html:10
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:17
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:17
t.getRegisteredRp @ popup.html:17
(anonymous) @ popup.html:17
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:17
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
b @ popup.html:10
popup.html:17 Error logging in with WebID-OIDC
(anonymous) @ popup.html:17
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:17
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
b @ popup.html:10
popup.html:17 TypeError: Cannot read property 'importKey' of undefined
    at e.value (popup.html:24)
    at Function.value (popup.html:24)
    at Function.value (popup.html:24)
    at popup.html:24
    at Array.map (<anonymous>)
    at Function.value (popup.html:24)
    at popup.html:24
(anonymous) @ popup.html:17
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:17
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
(anonymous) @ popup.html:24
_ @ popup.html:24
(anonymous) @ popup.html:24
e.(anonymous function) @ popup.html:24
o @ popup.html:10
(anonymous) @ popup.html:10
Promise.then (async)
o @ popup.html:10
(anonymous) @ popup.html:10
t @ popup.html:10
(anonymous) @ popup.html:10
(anonymous) @ popup.html:24
b @ popup.html:10

As reported by @oshanis and others.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.