Authenticate (Node.js Web Server)#
Inrupt provides the solid-client-authn-node
library to
authenticate in Node.js.
npm install @inrupt/solid-client-authn-node
For applications implementing Authorization Code Flow:
The application starts the login process by sending 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, where the application handles the returned authentication information to complete the login process.
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.
Create a new Session for the user at the login endpoint. By default, the Session is periodically refreshed in the background using the refresh token. You can override this periodic behavior by specifying
keepAlive: false
as a Session option to the Session constructor.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.
(Optional) Set to the display name for the client during the login process. When logging in, the user has to approve the client’s access to the requested data. The
clientName
is the name displayed during the approval step. IfclientName
is not provided, a random identifier is generated and used for the name.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.
- To make authenticated requests:
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:
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({ keepAlive: false }); // Turn off periodic refresh of the Session in background
req.session.sessionId = session.info.sessionId;
const redirectToSolidIdentityProvider = (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}/login/callback`,
// Set to the user's Solid Identity Provider; e.g., "https://login.inrupt.com"
oidcIssuer: "https://login.inrupt.com",
// Pick an application name that will be shown when asked
// to approve the application's access to the requested data.
clientName: "Demo app",
handleRedirect: redirectToSolidIdentityProvider,
});
});
app.get("/login/callback", 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 and 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) => {
if(typeof req.query["resource"] === "undefined") {
res.send(
"<p>Please pass the (encoded) URL of the Resource you want to fetch using `?resource=<resource URL>`.</p>"
);
}
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 [login.inrupt.com].`
);
});