Solid Auth Fetcher might still work against NSS and PSS, but it does not work against CSS and ESS.
Please use solid-client-authn instead.
A client tool to login and make authenticated requests to Solid compliant servers.
For use on the server-side (solid-node-client, solid-crud-tests, web-access-control-tests, etc.), we provide three special functions:
getNodeSolidServerCookie(serverRoot: string, username: string, password: string): Promise<string | null>
- POSTs to /login/password to get a cookie
- NSS-specific
getAuthFetcher(oidcIssuer: string, oidcProviderCookie: string, appOrigin: string): Promise<AuthFetcher>
- uses generic webid-oidc login
- relies on auth to IDP with cookie
- make sure the user has already authorized
appOriginas a trusted app
getAuthHeaders(urlStr: string, method: string, authFetcher): Promise<{Authorization: string; DPop: string }>
- will allow you to send the WebSockets
authanddpopheaders See ./examples/server for an example
npm install solid-auth-fetcher- In the web browser with your own bundler
- In the web browser with a script tag
- On the server
- In React Native (iOS and Andorid)
See the code in this html page, and try it out as follows:
git clone https://github.com/solid/solid-auth-fetcher.git cd solid-auth-fetcher cd examples/bundle # Edit the TEST_URL in line 10 of index.html to something on your own pod. npx serveNow browse to http://localhost:5000/
See for instance how the solid-crud-tests use solid-auth-fetcher to obtain the auth headers for use in websockets-pubsub or to test an authenticated DELETE request.
git clone https://github.com/solid/solid-auth-fetcher.git cd solid-auth-fetcher npm i npm run bootstrap-examples npm run build # Run each example npm run dev-bundle # npm run dev-script - see https://github.com/solid/solid-auth-fetcher/issues/9# npm run dev-server - see https://github.com/solid/solid-auth-fetcher/issues/8# npm run dev-ios - untested, see https://github.com/solid/solid-auth-fetcher/issues/10# npm run dev-android - untested, see https://github.com/solid/solid-auth-fetcher/issues/10At this point, a test application will be running on port 3001 and a test solid server will be running on port 9001
In the browser via the script tag:
<scriptsrc="/path/to/solidAuthFetcher.bundle.js"></script></script> solidAuthFetcher.getSession().then((session) =>{if (!session.loggedIn){console.log("User is not logged in") } else{console.log("User is logged in") } }) </script>Using import
import{getSession}from"solid-auth-fetcher"getSession().then((session)=>{if(!session.loggedIn){console.log("User is not logged in")}else{console.log("User is logged in")}})Using require
constsolidAuthFetcher=require("solid-auth-fetcher")solidAuthFetcher.getSession().then((session)=>{if(!session.loggedIn){console.log("User is not logged in")}else{console.log("User is logged in")}})Let's first see how we can initiate a login.
import{login,getSession}from'solid-auth-fetcher'// getSession will return a session objectgetSession().then(async(session)=>{if(!session){constsession=awaitlogin({// You could provide either a "webId" field, or an "oidcIssuer" field if// you know who the user's OIDC issuer is. If neither are provided, a// pop-up will ask the user to provide one. If it is running on the server// the popup parameter will be ingored.oidcIssuer: 'https://identityProvider.com',// Note that when 'popUp' is false, the browser will redirect the// current page thus stopping the current flow (default is false).popUp: false,// The page that that should be queried once login is completeredirect: 'https://mysite.com/redirect',})// Chances are that this session will not be logged in. Instead, your browser// window will be redirected and you'll be able to get the logged in session// via `getSession` or `onSession` after the redirect.console.log(session);}})By default, the user is redirected to the login page within the same window, but you might want to maintain the state of your application without it being interrupted by a redirect. To do so, you can use a popup.
The issuer's login page is opened in a popup, which then redirects the user to popUpRedirectPath. Running handleRedirect at this path stores the accessToken and webId in localStorage. The main window waits for the popup to close before creating the session from the stored credentials.
index.html:
<html><head><scriptsrc="/path/to/solidAuthFetcher.bundle.js"></script><script>functionlogin(){solidAuthFetcher.login({oidcIssuer: "https://identityProvider.com",popUp: true,popUpRedirectPath: "/popup.html"})}</script><head><body><buttononClick="login()">login</button></body></html>popup.html:
<html><head><scriptsrc="/path/to/solidAuthFetcher.bundle.js"></script><script>solidAuthFetcher.handleRedirect().then(()=>window.close());</script><head></html>Using getSession() to determine if a user is logged in is fine, but it's generally better to be alerted when a user has logged in. For this, you can use onSession(). Then you can use that user to fetch.
import{onSession}from'solid-auth-fetcher'onSession((session)=>{if(session.loggedIn){console.log(user.webId)session.fetch('https://example.com/resource')}})It is also possible to fetch without the "session" object. Keep in mind that doing so will not make an authenticated fetch if a user is not logged in.
import{fetch}from'solid-auth-fetcher'fetch('https://example.com/resource',{method: 'post',body: 'What a cool string!'}).then(async(response)=>{console.log(awaitresponse.text());})There may be some cases where you want to manage multiple users logged in at once. For this we can use the uniqueLogin function.
import{uniqueLogin,getSessions}from'solid-auth-fetcher'constmyWebId='https://example.com/profile/card#me'getSessions().then((sessions)=>{// If my WebID hasn't been logged in yet.if(sessions.some((session)=>session.webId===myWebId)){awaituniqueLogin({webId: myWebId,redirect: "https://myapp.com/redirect"})}})By default, Solid-Auth-Fetcher will use your browser's local storage. But, you may want to use your own implementation. To do so, you can use the getCustomAuthFetcher method and provide its own storage.
import{getCustomAuthFetcher}from'solid-auth-fetcher'getCustomAuthFetcher({storage: {// Key is a string and a Promise<string> should be returnedget: (key)=>{/* perform get */}// Key and value are both strings and a Promise<void> should be returnedset: (key,value)=>{/* perform set */}// Key is a string and a Promise<void> should be returneddelete: (key)=>{/* perform delete */}}}).then((authFetcher)=>{/* Do something */})By default, Solid-Auth-Fetcher redirects automatically upon login, and automatically handles a redirect back to the app when it is initialized. But, you may want to handle redirects manually. To do this you can use the doNotAutoRedirect and the doNotAutoHandleRedirect flags along with the handleRedirect method.
import{getCustomAuthFetcher}from'solid-auth-fetcher'// Get the custom auth fetcher that will not trigger `handleRedirect` automaticallygetCustomAuthFetcher({doNotAuthHandleRedirect: true}).then(async(authFetcher)=>{// If we are at the redirect location we want to handle itif(window.location.pathname==="/redirect"){// Call the handleRedirect method with the current urlawaitauthFetcher.handleRedirect(window.location.href);// Once the redirect is handled we can return to the home pagewindow.history.replaceState({},"",window.location.origin)// If we are not at the redirect route we should trigger a log in or get// the session}else{constcurSession=awaitgetSession()if(curSession.loggedIn){console.log("The user is logged in");}else{// Log in if the user is not alreadyconstsession=awaitauthFetcher.login({oidcIssuer: 'https://identityProvider.com',redirect: 'https://mysite.com/redirect',// Notice this flag the suppresses the auto redirectdoNotAutoRedirect: true});// Because we have suppressed the redirect, the session will not// be logged in, but rather have a "NeededAction" object that will// describe where we should redirectif(session.neededAction&&session.neededAction.actionType==="redirect"){// Perform the manual redirectwindow.location.href=session.neededAction.redirectUrl}}}})See examples/server/src/server.ts.
login(options): Session
Kick off the login process for a global user:
import{login}from'solid-auth-fetcher';login({// You could provide either a "webId" field, or an "issuer"// field if you know who the user's OIDC issuer is. If// neither are provided, a pop-up will ask the user to// provide one.webId: 'https://example.com/profile/card#me',// Note that when 'popUp' is false, the browser will// redirect the current page thus stopping the current// flow (default is false).popUp: false,redirect: 'https://mysite.com/redirect'}).then((session)=>{console.log("Please visit",(session.neededActionasany).redirectUrl);})It will print something like
Please visit https://localhost:8443/authorize?response_type=id_token%20code&redirect_uri=https%3A%2F%2Fmysite.com%2Fredirect&scope=openid%20profile%20offline_access&client_id=636e3fec47416ca31d58d15344ebdfda&code_challenge_method=S256&code_challenge=5J6v7lYziRQ8yqKCsF6JsxvoLHvZjpNMt1iiJSQgdQU&state=global Options:
| Field Name | Required? | Type | Description | Default |
|---|---|---|---|---|
webId | Yes, unless issuer is provided | String or URL | The user's WebID | undefined |
issuer | Yes, unless webId is provided | String or URL | The user's issuer | undefined |
redirect | Yes | String or URL | The URI within this application that the user should be redirected to after successful login. This can be either a web URL or a mobile URL scheme | undefined |
clientId | In the current spec, no, in the upcoming spec, yes | String or URL | The app's WebID | undefined |
popUp | No | Boolean | If true, the login process will initiate via a popup. This only works on web clients. | false |
popUpRedirectPath | No | String | The path to which a popup window should redirect after the user is logged in | undefined |
state | No | String | The state will be provided with the User's Session object once they have logged in | undefined |
doNotAutoRedirect | No | Boolean | If true, the browser will not auto redirect. Note that auto redirect only happens if Solid-Auth-Fetcher is running in the browser | false |
uniqueLogin(options): Session
Kick off the login process for a unique user. This allows you to log in multiple users with solid-auth-fetcher. It's a useful feature for apps that wish to support multiple users being logged into the same client, or for servers that work with multiple clients.
import{uniqueLogin}from'solid-auth-fetcher';uniqueLogin({webId: 'https://example.com/profile/card#me',popUp: falseredirect: 'https://mysite.com/redirect'}).then((session)=>{})The options for uniqueLogin() are identical to login().
Send an HTTP request to a Solid Pod as the global user:
import{fetch}from'solid-auth-fetcher';fetch('https://example.com/resource',{method: 'POST',headers: {"Content-Type": "text/plain"},body: 'Sweet body, bro'}).then((result)=>{})Fetch follows the WHATWG Fetch Standard.
Log the global user out:
import{logout}from'solid-auth-fetcher';logout().then(()=>{})getSession(): Session
Retrieve the session for the global user:
import{getSession}from'solid-auth-fetcher';awaitgetSession().then((session)=>{})getSessions(): Session[]
Retrieve all sessions currently registered with authFetcher
import{getSessions}from'solid-auth-fetcher';awaitgetSessions().then((sessions)=>{})Register a callback function to be called when a new session is received after the user has logged in:
import{onSession}from'solid-auth-fetcher'onSession((session)=>{console.log(session.webId)})The callback receives a Session object as its sole parameter.
Register a callback function to be called when a session is logged out:
import{onLogout}from'solid-auth-fetcher'onLogout((session)=>{console.log(session.webId)})Register a callback function to be called whenever a request is made:
import{onRequest}from'solid-auth-fetcher'onRequest((url,requestOptions)=>{console.log(url)})The session object contains information about the logged in user, as well as functions that can be executed as that user (e.g. logout()).
interfaceSession{localUserId: String// The id to internally track this sessionloggedIn: Boolean// True if this session is logged inwebId?: String// The user's WebID.state?: String// Any state that was passed upon login.neededAction?: {actionType: "redirect"|"inaction"}// Indicates that you must execute some action to continue.logout: ()=>void// Function to log this user out.fetch: (url: string,options: {}): Promise<Result>// Function to fetch as this user}Handle redirects as a part of the OIDC process. Servers using solid-auth-fetcher must manually call this method on redirect, but is done automatically on web and mobile.
import{handleRedirect}from'solid-auth-fetcher'handleRedirect(window.location.href).then((session)=>{})Create an instance of AuthFetcher with configurable settings:
importcustomAuthFetcherfrom'solid-auth-fetcher'constauthFetcher=customAuthFetcher({// A custom implementation of how auth fetcher should persist its// data.storage: {get: (key: string)=>Promise<any>set: (key: string,value: any)=>Promise<void>delete: (key: string)=>Promise<void>},// If true, handleRedirect will automatically be triggered on web// and mobile platforms. Default is true. shouldAutoHandleRedirect: boolean})The primary object for logging in, and making authenticated fetches:
interfaceAuthFetcher{login: (options: {})=>Promise<void>fetch: (url: string|URL,options: {})=>Promise<Response>logout: ()=>Promise<void>getSession: ()=>Promise<Session>getSessions: ()=>Promise<Session[]>uniqueLogin: (options: {})=>Promise<void>onSession: (callback: (session: Session)=>any)=>voidonLogout: (callback: (session: Session)=>any)=>voidhandleRedirect: (url: string|URL)=>Promise<void>}Any part of solid-auth-fetcher can be modified without the need to commit to the source library. All you need to do is build up a dependency injection heirarchy as seen in https://github.com/inrupt/solid-auth-fetcher/blob/refactor/src/dependencies.ts.