The UserInfo Endpoint
The /userinfo endpoint returns the Scope-Derived Claims of the end-user for an Access Token (OpenID Connect Core §5.3). The Client sends the Access Token that it received from the /token endpoint, and gets the claims that the granted scopes permit.
authorizationServer.userInfo(req) returns a promise of a ResponseInterface. This is a 200 with the claims, or an RFC 6750 bearer error. Thus every adapter handles it in the usual way.
INFO
- You must enable OIDC. Set the
issueroption, and theoidcblock withgetUserClaims. - The server must have granted the
openidscope for the Access Token. - The
AccessTokenVerifierverifies the Access Token. It pins the signing algorithm, it makes thetyp: at+jwtJOSE header mandatory, and it checks the Issuer.
app.get("/userinfo", async (req: Express.Request, res: Express.Response) => {
try {
const oauthResponse = await authorizationServer.userInfo(req);
return handleExpressResponse(res, oauthResponse);
} catch (e) {
handleExpressError(e, res);
return;
}
});Request
The server reads the Access Token from two places, in this sequence:
- The
Authorization: Bearer <token>header. - The
access_tokenparameter in the form body.
The server does not accept the query parameter from RFC 6750 §2.3. A token in a URL goes into the access logs, the browser history, and the Referer headers.
GET /userinfo HTTP/1.1
Host: auth.example.com
Authorization: Bearer <access_token>Response
A correct response is a 200 OK with Content-Type: application/json and Cache-Control: no-store. The body holds the sub and each claim that the granted scopes permit. The scope-to-claim map shows which scope permits which claim. Your getUserClaims(subject) callback supplies the attributes, and the library then removes the claims that the scopes do not permit.
{
"sub": "248289761001",
"name": "Jane Doe",
"email": "[email protected]",
"email_verified": true
}The server controls sub
The sub claim always comes from the canonical subject of the Access Token, and the library writes it last. Thus your getUserClaims callback cannot change it. This sub is identical to the sub in the ID Token.
Errors
Each error obeys RFC 6750, and carries a WWW-Authenticate: Bearer challenge.
| Condition | Status | WWW-Authenticate |
|---|---|---|
Missing, malformed, expired, wrong typ, wrong iss, or revoked token | 401 | Bearer error="invalid_token", error_description="<reason>" |
Valid token without the openid scope | 403 | Bearer error="insufficient_scope", error_description="openid scope required", scope="openid" |
The server rejects a revoked Access Token with invalid_token, but only when your token repository has getByAccessToken. With getByAccessToken alone, a token is revoked when you delete it from storage, or when its stored expiry passes.
If your revoke() marks a row as revoked, and keeps the row with a future expiry, also write the optional isAccessTokenRevoked method. UserInfo calls it before it returns the claims.
The audience policy in the first OIDC release
The first OIDC release accepts each Access Token that this server issued, and it identifies these tokens by the iss claim. It makes no audience check. An audience check for one resource server comes later, when the audience parameter has a place in the Discovery Document.
Supports the following specifications
OpenID Connect Core 1.0 §5.3 (UserInfo Endpoint), RFC 6750 (Bearer Token Usage)