UNPKG

oidc-provider

Version:

OAuth 2.0 Authorization Server implementation for Node.js with OpenID Connect

163 lines (131 loc) 4.07 kB
/* eslint-disable camelcase */ import * as errors from '../../errors.js'; import instance from '../../weak_cache.js'; import Prompt from '../prompt.js'; import Check from '../check.js'; export default () => new Prompt( { name: 'login', requestable: true }, (ctx) => { const { oidc } = ctx; return { ...(oidc.params.max_age === undefined ? undefined : { max_age: oidc.params.max_age }), ...(oidc.params.login_hint === undefined ? undefined : { login_hint: oidc.params.login_hint }), ...(oidc.params.id_token_hint === undefined ? undefined : { id_token_hint: oidc.params.id_token_hint }), }; }, new Check('no_session', 'End-User authentication is required', (ctx) => { const { oidc } = ctx; if (oidc.session.accountId) { return Check.NO_NEED_TO_PROMPT; } return Check.REQUEST_PROMPT; }), new Check('max_age', 'End-User authentication could not be obtained', (ctx) => { const { oidc } = ctx; if (oidc.params.max_age === undefined) { return Check.NO_NEED_TO_PROMPT; } if (!oidc.session.accountId) { return Check.REQUEST_PROMPT; } if (oidc.session.past(oidc.params.max_age) && (!ctx.oidc.result || !ctx.oidc.result.login)) { return Check.REQUEST_PROMPT; } return Check.NO_NEED_TO_PROMPT; }), new Check( 'id_token_hint', 'id_token_hint and authenticated subject do not match', async (ctx) => { const { oidc } = ctx; if (oidc.entities.IdTokenHint === undefined) { return Check.NO_NEED_TO_PROMPT; } const { payload } = oidc.entities.IdTokenHint; let sub = oidc.session.accountId; if (sub === undefined) { return Check.REQUEST_PROMPT; } if (oidc.client.subjectType === 'pairwise') { sub = await instance(oidc.provider).configuration.pairwiseIdentifier( ctx, sub, oidc.client, ); } if (payload.sub !== sub) { return Check.REQUEST_PROMPT; } return Check.NO_NEED_TO_PROMPT; }, ), new Check( 'claims_id_token_sub_value', 'requested subject could not be obtained', async (ctx) => { const { oidc } = ctx; if ( !oidc.claims.id_token || !oidc.claims.id_token.sub || !('value' in oidc.claims.id_token.sub) ) { return Check.NO_NEED_TO_PROMPT; } let sub = oidc.session.accountId; if (sub === undefined) { return Check.REQUEST_PROMPT; } if (oidc.client.subjectType === 'pairwise') { sub = await instance(oidc.provider).configuration.pairwiseIdentifier( ctx, sub, oidc.client, ); } if (oidc.claims.id_token.sub.value !== sub) { return Check.REQUEST_PROMPT; } return Check.NO_NEED_TO_PROMPT; }, ({ oidc }) => ({ sub: oidc.claims.id_token.sub }), ), new Check( 'essential_acrs', 'none of the requested ACRs could not be obtained', (ctx) => { const { oidc } = ctx; const request = oidc.claims?.id_token?.acr ?? {}; if (!request?.essential || !request?.values) { return Check.NO_NEED_TO_PROMPT; } if (!Array.isArray(oidc.claims.id_token.acr.values)) { throw new errors.InvalidRequest('invalid claims.id_token.acr.values type'); } if (request.values.includes(oidc.acr)) { return Check.NO_NEED_TO_PROMPT; } return Check.REQUEST_PROMPT; }, ({ oidc }) => ({ acr: oidc.claims.id_token.acr }), ), new Check( 'essential_acr', 'requested ACR could not be obtained', (ctx) => { const { oidc } = ctx; const request = oidc.claims?.id_token?.acr ?? {}; if (!request?.essential || !request?.value) { return Check.NO_NEED_TO_PROMPT; } if (request.value === oidc.acr) { return Check.NO_NEED_TO_PROMPT; } return Check.REQUEST_PROMPT; }, ({ oidc }) => ({ acr: oidc.claims.id_token.acr }), ), );