Node.js without a framework
The authorization flow on openid-client, when Auth.js does not fit.
npm install openid-client
Setup
import * as client from 'openid-client'
const config = await client.discovery(
new URL('https://auth.my'),
process.env.AUTHMY_CLIENT_ID,
process.env.AUTHMY_CLIENT_SECRET,
)
One call fetches endpoints, keys and algorithms. You do not list them yourself.
Send the user to sign in
const codeVerifier = client.randomPKCECodeVerifier()
const state = client.randomState()
const nonce = client.randomNonce()
const url = client.buildAuthorizationUrl(config, {
redirect_uri: 'https://example.com/callback',
scope: 'openid profile email',
code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
code_challenge_method: 'S256',
state,
nonce,
})
Important
codeVerifier, state and nonce must survive between the two requests —
in a server-side session or a signed cookie. Without state you cannot
tell your own user's return from one planted by someone else.
Handle the return
const tokens = await client.authorizationCodeGrant(config, currentUrl, {
pkceCodeVerifier: codeVerifier,
expectedState: state,
expectedNonce: nonce,
})
const claims = tokens.claims()
claims.sub // permanent identifier — store this one
claims.email // the profile is inside the id_token
tokens.access_token // for requests to /me
tokens.refresh_token // issued without asking
Signature, expiry, issuer and nonce are all verified by the library inside
authorizationCodeGrant.
Fresh profile data
const profile = await client.fetchUserInfo(config, tokens.access_token, claims.sub)
Only needed if the data may have changed since sign-in: name and email
already arrived in the id_token.
Refresh
const fresh = await client.refreshTokenGrant(config, tokens.refresh_token)
The response carries a new refresh token. Store it in place of the old one — details and pitfalls in Tokens.
Did this page help?