Skip to main content
Version: 1.x

Express: Integrate @logto/express

note

This tutorial assumes you have created an Application of type "Traditional Web" in Admin Console. If you are not ready, read this before continuing.

Add dependenciesโ€‹

npm i @logto/express cookie-parser express-session

Init LogtoClientโ€‹

note

In the following code snippets, we assume your app is running on http://localhost:3000.

tip

You can find and copy "App Secret" from application details page in Admin Console:

App Secret

Import and initialize LogtoClient:

import { LogtoExpressConfig } from '@logto/express';

const config: LogtoExpressConfig = {
appId: '<your-application-id>',
appSecret: '<your-application-secret>',
endpoint: '<your-logto-endpoint>', // E.g. http://localhost:3001
baseUrl: '<your-express-app-base-url>', // E.g. http://localhost:3000
};

Prepare required middlewaresโ€‹

The SDK requires express-session to be configured in prior.

import cookieParser from 'cookie-parser';
import session from 'express-session';

app.use(cookieParser());
app.use(
session({
secret: 'random_session_key',
cookie: { maxAge: 14 * 24 * 60 * 60 * 1000 }, // In miliseconds
})
);

Sign inโ€‹

The sign-in flow can be simplified as:

Web sign-in flow

Configure sign-in redirect URIโ€‹

Let's switch to the Application details page of Admin Console in this section. Add a Redirect URI http://localhost:3000/logto/sign-in-callback and click "Save Changes".

Redirect URI in Admin Console

Redirect URI is an OAuth 2.0 concept which implies the location should redirect after authentication.

Prepare logto routesโ€‹

Prepare routes to connect with Logto.

Go back to your IDE/editor, use the following code to implement the API routes first:

import { handleAuthRoutes } from '@logto/express';

app.use(handleAuthRoutes(config));

This will create 3 routes automatically:

  1. /logto/sign-in: Sign in with Logto.
  2. /logto/sign-in-callback: Handle sign-in callback.
  3. /logto/sign-out: Sign out from Logto.

Implement sign-inโ€‹

We're almost there! Now, create a sign-in button to redirect to the sign-in route on user click.

app.get('/', (req, res) => {
res.setHeader('content-type', 'text/html');
res.end(`<div><a href="/logto/sign-in">Sign In</a></div>`);
});

Get user profileโ€‹

In order to get user profile, we need to use the withLogto middleware:

import { withLogto } from '@logto/express';

app.use(withLogto(config));

Then the user profile will be attached to req, example usage:

app.get('/user', (req, res) => {
res.json(req.user);
});

Fetch user infoโ€‹

For most cases, it is recommended to use claims in req.user as "user info", this can be fast because claims is cached when tokens are granted. If you need more accurate user info, set config.fetchUserInfo to true, to tell the SDK to fetch the user information from the OIDC UserInfo Endpoint.

app.get('/user', withLogto({ ...config, fetchUserInfo: true }), (req, res) => {
res.json(req.user.userInfo);
});

The user information response will vary based on the scopes used in the LogtoConfig while initializing the LogtoClient; and the following table lists the relations between user information and scopes:

Field NameTypeRequired ScopeNotes
substringopenidThe openid scope is added by default.
namestringprofileThe profile scope is added by default.
usernamestringprofileThe profile scope is added by default.
picturestringprofileThe profile scope is added by default.
emailstringemail
email_verifiedbooleanemail
phone_numberstringphone
phone_number_verifiedbooleanphone
custom_dataobjectcustom_data
identitiesobjectidentities

Protect routesโ€‹

After setting up withLogto in the previous step, we can protect routes by creating a simple middleware:

const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
if (!req.user.isAuthenticated) {
res.redirect('/logto/sign-in');
}

next();
};

And then:

app.get('/protected', requireAuth, (req, res) => {
res.end('protected resource');
});

Get access tokenโ€‹

If you want to get the access token, set getAccessToken to true:

app.get(
'/fetch-access-token',
withLogto({
...config,
// Fetch access token from remote, this may slow down the response time,
// you can also add "resource" if needed.
getAccessToken: true,
}),
(request, response) => {
// Get access token here
console.log(request.user.accessToken);
response.json(request.user);
}
);

Sign outโ€‹

Calling /logto/sign-out will clear all the Logto data in memory and cookies if they exist.

After signing out, it'll be great to redirect your user back to your website. Let's add http://localhost:3000 as one of the Post Sign-out URIs in Admin Console (shows under Redirect URIs).

Further readingsโ€‹