node-oidc-provider 7.12.0:UserInfo端点JWT令牌invalid_token错误
Node-oidc-provider 7.12.0 启用resourceIndicators后JWT类型AccessToken调用UserInfo端点报invalid_token错误
在使用node-oidc-provider 7.12.0的authorization_code模式时,启用resourceIndicators配置后,使用JWT类型AccessToken调用UserInfo(/me)端点会返回invalid_token错误;注释掉resourceIndicators部分则功能正常。可通过PostMan正常获取AccessToken,但携带该令牌调用/me端点时失败。已尝试多种配置均未解决,相关代码及生成的JWT内容如下:
const {Provider} = require('oidc-provider'); let hostname = process.env.HOSTNAME; if (hostname === undefined) { hostname = "http://localhost" } const port = process.env.PORT || 3000; if (port !== 80 && port !== 443) { hostname = hostname + ':' + port } const users = [ { "id": "user1", "email": "user1@example.com", "authentication_method_reference": "mfa" } ] const clients = [ { "client_id": "client-1", "client_secret": "client-1-secret", "redirect_uris": [ "http://localhost:3000" ] } ] async function findAccount (ctx, id) { // This would ideally be just a check whether the account is still in your storage let account = users.find(user => { return user.id === id; }) if (!account) { return undefined; } return { accountId: id, async claims() { return { sub: id, email: account.email, amr: [account.authentication_method_reference] }; }, }; } const configuration = { clients: clients, conformIdTokenClaims: false, features: { devInteractions: { enabled: true }, resourceIndicators: { defaultResource: (ctx, client, oneOf) => { return hostname; }, enabled: true, getResourceServerInfo: (ctx, resourceIndicator, client) => { console.log('get resource server info', client); return ({ audience: resourceIndicator, scope: 'openid', accessTokenTTL: 2 * 60 * 60, accessTokenFormat: 'jwt', }); }, useGrantedResource: (ctx, model) => { return true; } } }, claims: { openid: [ 'sub', 'email', 'amr' ] }, cookies: { keys: 'super,secret'.split(',') }, pkce: { required: () => false }, // Used to skip the 'approval' page async loadExistingGrant(ctx) { const grantId = (ctx.oidc.result && ctx.oidc.result.consent && ctx.oidc.result.consent.grantId) || ctx.oidc.session.grantIdFor(ctx.oidc.client.clientId); if (grantId) { // keep grant expiry aligned with session expiry // to prevent consent prompt being requested when grant expires const grant = await ctx.oidc.provider.Grant.find(grantId); // this aligns the Grant ttl with that of the current session // if the same Grant is used for multiple sessions, or is set // to never expire, you probably do not want this in your code if (ctx.oidc.account && grant.exp < ctx.oidc.session.exp) { grant.exp = ctx.oidc.session.exp; await grant.save(); } return grant; } else { const grant = new ctx.oidc.provider.Grant({ clientId: ctx.oidc.client.clientId, accountId: ctx.oidc.session.accountId, }); grant.addOIDCScope('openid'); grant.addResourceScope(hostname, 'openid'); await grant.save(); return grant; } }, extraTokenClaims: async (ctx, token) => { return findAccount(ctx, token.accountId).then(account => { return account.claims() }) }, findAccount: findAccount }; const oidc = new Provider(hostname, configuration); function handleServerError(ctx, err) { console.log(err); } function handleGrantErrors({headers: {authorization}, oidc: {body, client}}, err) { console.log(err); } function handleAccessToken(token) { console.log(token); } oidc.on('grant.error', handleGrantErrors); oidc.on('introspection.error', handleGrantErrors); oidc.on('revocation.error', handleGrantErrors); oidc.on('server_error', handleServerError); oidc.on('access_token.issued', handleAccessToken); oidc.listen(port, () => { console.log(`oidc-provider listening on port ${port}.`) })
生成的JWT内容:
{ "sub": "user1", "email": "user1@example.com", "amr": [ "mfa" ], "jti": "-7gURc8Y1SXqOXhWR691i", "iat": 1668777371, "exp": 1668784571, "scope": "openid", "client_id": "client-1", "iss": "http://localhost:3000", "aud": "http://localhost:3000" }
内容的提问来源于stack exchange,提问作者F0x06
相关产品推荐
相关产品推荐

