Authenticate¶
To access private data on Solid Pods, you must authenticate as a user/agent who has been granted appropriate access to that data. For example, to write to a resource, the user must have Write Access on the Resource.
Authentication in Solid is based on OpenID Connect (OIDC), which means the authentication has the following flow:
The application sends the user to the user’s Solid Identity Provider.
The user logs in to the Solid Identity Provider.
The Solid Identity Provider sends the user back to your application.
Important
The login is only complete after the user is redirected back to the app; i.e., your application must be reloaded between the start of the login and its completion.
Inrupt provides the following libraries for authentication:
solid-client-authn-browser
library to authenticate in a browser.solid-client-authn-node
library to authenticate in Node.js.
In a Browser Environment¶
To authenticate in a browser environment, you can use the
solid-client-authn-browser
library.
Call the login() function to start the process. Pass in the following login options:
Set to the user’s Solid Identity Provider (where the login function will send the user).
Set to the location that the Solid Identity Provider will send the user back once logged in.
For other options available to the function, see ILoginInputOptions.
This process redirects the user from your application to the Solid Identity Provider. Once redirected to the Solid Identity Provider, the user logs in. Upon successful login, the Solid Identity Provider sends the user back to your application.
To complete the login process, call handleIncomingRedirect() to collect the information provided by the Solid Identity Provider when it redirects the user back to your application. The session is logged in only after it handles the incoming redirect from the Solid Identity Provider.
Once logged in, the fetch() function can retrieve data using the available login information.
You can pass this fetch() function as an option to the
solid-client
functions (e.g., getSolidDataset, saveSolidDatasetAt) to include the user’s credentials with a request.
Example¶
The following example uses the solid-client-authn-browser
library
to login to a Solid server. It passes the fetch() function as an option to the
solid-client
functions getSolidDataset and
saveSolidDatasetAt to read and
write data to a Pod where the logged-in user has the appropriate
access.
import { handleIncomingRedirect, login, fetch, getDefaultSession } from '@inrupt/solid-client-authn-browser'
import { getSolidDataset, saveSolidDatasetAt } from "@inrupt/solid-client";
async function loginAndFetch() {
// 1. Call the handleIncomingRedirect() function to complete the authentication process.
// If the page is being loaded after the redirect from the Solid Identity Provider
// (i.e., part of the authentication flow), the user's credentials are stored in-memory, and
// the login process is complete. That is, a session is logged in
// only after it handles the incoming redirect from the Solid Identity Provider.
// If the page is not being loaded after a redirect from the Solid Identity Provider,
// nothing happens.
await handleIncomingRedirect();
// 2. Start the Login Process if not already logged in.
if (!getDefaultSession().info.isLoggedIn) {
// The `login()` redirects the user to their identity provider;
// i.e., moves the user away from the current page.
await login({
// Specify the URL of the user's Solid Identity Provider; e.g., "https://inrupt.net"
oidcIssuer: "https://inrupt.net",
// Specify the URL the Solid Identity Provider should redirect to after the user logs in,
// e.g., the current page for a single-page app.
redirectUrl: window.location.href,
});
}
// 3. Make authenticated requests by passing `fetch` to the solid-client functions.
// The user must have logged in as someone with the appropriate access to the specified URL.
// For example, the user must be someone with Read access to the specified URL.
const myDataset = await getSolidDataset(
"https://docs-example.inrupt.net/profile/card", {
fetch: fetch
});
// ...
// For example, the user must be someone with Write access to the specified URL.
const savedSolidDataset = await saveSolidDatasetAt(
"https://docs-example.inrupt.net/profile/card",
myChangedDataset, {
fetch: fetch
});
}
loginAndFetch();
For working examples, you can look at the sample apps distributed with the code:
In a Node.js Environment¶
To authenticate in a Node.js environment, you can use the
solid-client-authn-node
library.
Node.js Web Server: Multi-session Management¶
A Node.js web server can use the solid-client-authn-node
library to
handle the user authentication flow and manage multiple sessions.
Session Management
To manage sessions, solid-client-authn-node
automatically stores
a mapping of the Session ID to Session when starting the login
process. To retrieve the correct session for a user,
solid-client-authn-node
provides the
getSessionFromStorage() function that takes
a Session ID as its argument.
Logging out a session removes the session from the storage as well as disables its access to private resources.
Create a new Session for the user at the login endpoint.
Call the Session.login() function to start the login process. Pass in the following login options:
Set to the user’s Solid Identity Provider (where
handleRedirect
will send the user).Set to the location that the Solid Identity Provider will send the user back once logged in.
Set to a callback function that sends users to their Solid Identity Provider.
For other options available to the function, see ILoginInputOptions.
This process redirects the user from your application to the Solid Identity Provider. Once redirected to the Solid Identity Provider, the user logs in. Upon successful login, the Solid Identity Provider sends the user back to your application.
Use getSessionFromStorage() to retrieve the correct session for the user. Pass in the Session ID.
To complete the login process, call Session.handleIncomingRedirect(), passing in the URL of the page handling the redirect. Session.handleIncomingRedirect() collects the session information provided by the Solid Identity Provider. Because this information is appended to the URL as query parameters, pass the function the full URL.
After Session.handleIncomingRedirect() returns, your session is logged in.
Once logged in, the
Session
object provides a fetch() function that retrieves data using available login information.You can pass this fetch() function as an option to the
solid-client
functions (e.g., getSolidDataset, saveSolidDatasetAt) to include the user’s credentials with a request.To log out a session, call the session’s logout() method.
Logging out a session removes the session from the storage as well as disables its access to private resources.
To get a list of all the sessions currently in storage, you can call getSessionIdFromStorageAll().
Example¶
The following Express server example uses
the solid-client-authn-node
library to log in to a Solid server.
Note
In the example, the cookie-session
Express middleware is used to
associate the session ID to the user’s browser through a cookie.
const express = require("express");
const cookieSession = require("cookie-session");
const {
getSessionFromStorage,
getSessionIdFromStorageAll,
Session
} = require("@inrupt/solid-client-authn-node");
const app = express();
const port = 3000;
// The following snippet ensures that the server identifies each user's session
// with a cookie using an express-specific mechanism
app.use(
cookieSession({
name: "session",
// These keys are required by cookie-session to sign the cookies.
keys: [
"Required, but value not relevant for this demo - key1",
"Required, but value not relevant for this demo - key2",
],
maxAge: 24 * 60 * 60 * 1000, // 24 hours
})
);
app.get("/login", async (req, res, next) => {
// 1. Create a new Session
const session = new Session();
req.session.sessionId = session.info.sessionId;
const redirectHandler = (url) => {
// Since we use Express in this example, we can call `res.redirect` to send the user to the
// given URL, but the specific method of redirection depend on your app's particular setup.
// For example, if you are writing a command line app, this might simply display a prompt for
// the user to visit the given URL in their browser.
res.redirect(url);
};
// 2. Start the login process; redirect handler will handle sending the user to their
// Solid Identity Provider.
await session.login({
// After login, the Solid Identity Provider will send the user back to the following
// URL, with the data necessary to complete the authentication process
// appended as query parameters:
redirectUrl: `http://localhost:${port}/handle-redirect`,
// Set to the user's Solid Identity Provider; e.g., "https://broker.pod.inrupt.com"
oidcIssuer: "https://broker.pod.inrupt.com",
clientName: "Demo app",
handleRedirect: redirectHandler,
});
});
app.get("/handle-redirect", async (req, res) => {
// 3. If the user is sent back to the `redirectUrl` provided in step 2,
// it means that the login has been initiated an can be completed. In
// particular, initiating the login stores the session in storage,
// which means it can be retrieved as follows.
const session = await getSessionFromStorage(req.session.sessionId);
// 4. With your session back from storage, you are now able to
// complete the login process using the data appended to it as query
// parameters in req.url by the Solid Identity Provider:
await session.handleIncomingRedirect(`http://localhost:${port}${req.url}`);
// 5. `session` now contains an authenticated Session instance.
if (session.info.isLoggedIn) {
return res.send(`<p>Logged in with the WebID ${session.info.webId}.</p>`)
}
});
// 6. Once you are logged in, you can retrieve the session from storage,
// and perform authenticated fetches.
app.get("/fetch", async (req, res, next) => {
const session = await getSessionFromStorage(req.session.sessionId);
console.log(await (await session.fetch(req.query["resource"])).text());
res.send("<p>Performed authenticated fetch.</p>");
});
// 7. To log out a session, just retrieve the session from storage, and
// call the .logout method.
app.get("/logout", async (req, res, next) => {
const session = await getSessionFromStorage(req.session.sessionId);
session.logout();
res.send(`<p>Logged out.</p>`);
});
// 8. On the server side, you can also list all registered sessions using the
// getSessionIdFromStorageAll function.
app.get("/", async (req, res, next) => {
const sessionIds = await getSessionIdFromStorageAll();
for(const sessionId in sessionIds) {
// Do something with the session ID...
}
res.send(
`<p>There are currently [${sessionIds.length}] visitors.</p>`
);
});
app.listen(port, () => {
console.log(
`Server running on port [${port}]. ` +
`Visit [http://localhost:${port}/login] to log in to [broker.pod.inrupt.com].`
);
});
Node.js Script: Single-User Script¶
A Node.js script can use the solid-client-authn-node
library to
handle the user authentication flow.
Create a new Session for the user.
Call the Session.login() function, passing in ILoginInputOptions.
Although you can pass in options to start the authentication flow, you can also pass in the following options to have an authenticated session without the manual, in-browser redirect interactions:
An already-registered clientId, which identifies your application to the Solid Identity Provider.
An already-registered clientSecret, associated to the Client ID.
An already-registered refreshToken, which your application can use to get an Access Token. Access Tokens allows you to access Resources for which you have been authorized.
oidcIssuer, the Solid Identity Provider where your
Client ID
,Client Secret
, andRefresh Token
have been registered.
When
login()
returns, your session should be logged in and able to make authenticated requests.
Warning
Safeguard your clientId
, clientSecret
, and refreshToken
values. Do not share these with any third parties as anyone with
your clientId
, clientSecret
, and refreshToken
values can
impersonate you and act fully on your behalf.
Example¶
The following single-user script calls Session.login() with:
clientId
,clientSecret
,refreshToken
, andoidcIssuer
.
Warning
Safeguard your clientId
, clientSecret
, and refreshToken
values. Do not share these with any third parties as anyone with
your clientId
, clientSecret
, and refreshToken
values can
impersonate you and act fully on your behalf.
const { Session } = require("@inrupt/solid-client-authn-node");
// 1. Get the authenticated credentials: myClientId, myClientSecret, myRefreshToken
// ...
// ...
// Important: Safeguard these credentials.
const session = new Session();
session.login({
// 2. Use the authenticated credentials to log in the session.
clientId: myClientId,
clientSecret: myClientSecret,
refreshToken: myRefreshToken,
// Set oidcIssuer to the Solid Identity Provider associated with the credentials.
oidcIssuer: "https://broker.pod.inrupt.com",
}).then(() => {
if (session.info.isLoggedIn) {
// 3. Your session should now be logged in, and able to make authenticated requests.
session
// You can change the fetched URL to a private resource, such as your Pod root.
.fetch(session.info.webId)
.then((response) => {
return response.text();
})
.then(console.log);
}
});
Additional Reference¶
@inrupt/generate-oidc-token
Utility¶
As mentioned in the introduction, Solid authentication involves redirecting the user in a browser to the Solid Identity Provider, and after the user logs in, redirecting the user back to the specified URL.
To help during the development of a single-user Node.js script, Inrupt provides a utility @inrupt/generate-oidc-token. The standalone utility takes a user through the authentication flow and upon successful authentication, outputs the Client ID, Client Secret , and Refresh Token.
Note
The utility only supports logging in to Solid-OIDC compliant Identity Provider, such as
https://broker.pod.inrupt.com
andhttps://broker.pod-compat.inrupt.com
.The utility outputs credentials that expire after 3 days.
In a terminal, run
generate-oidc-token
utility to log in to anpx @inrupt/generate-oidc-token
The utility prompts the user for some information.
Enter the appropriate values to the prompts.
When finished, the utility asks the user to visit a site in a browser.
Open the browser and visit the site. Log in to the Solid Identity Provider.
Upon login, return to the terminal and you should see the following information:
Client ID
Client Secret
Refresh Token
Warning
Safeguard your Client ID
, Client Secret
, and Refresh
Token
values. Do not share these with any third parties as anyone with
your Client ID
, Client Secret
, and Refresh Token
values can
impersonate you and act fully on your behalf.