首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >节点-oidc-provider 7.12.0 (JWT,authorization_code) UserInfo端点(/me)上的invalid_token错误

节点-oidc-provider 7.12.0 (JWT,authorization_code) UserInfo端点(/me)上的invalid_token错误
EN

Stack Overflow用户
提问于 2022-11-18 13:19:32
回答 1查看 44关注 0票数 0

我在让UserInfo端点使用JWT AccessTokens时遇到了一些问题,在注释掉resourceIndicators部分时,它可以很好地处理默认设置。

我可以使用PostMan获得访问令牌,而不会出现问题,但是当在UserInfo (/me)端点Bearer AccessToken上投递时,我得到了一个invalid_token错误。

这是我的代码:

代码语言:javascript
复制
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 AccessToken在我看来很好(请参阅下面),但我无法用它查询UserInfo端点。

代码语言:javascript
复制
{
  "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"
}

提前谢谢。

EN

回答 1

Stack Overflow用户

发布于 2022-11-19 09:10:58

根据模块文档的用户信息特性。

它的使用需要一个不透明的访问令牌,该令牌至少具有openid作用域,而没有资源服务器对象。

本质上,此实现的userinfo端点将不适用于为特定资源服务器发出的JWT访问令牌。这是因为userinfo端点是客户端的资源,如果可以使用发送到资源服务器的访问令牌调用它,那么该资源服务器可以反过来查询userinfo,这不是userinfo端点的预期用途。

在发出JWT访问令牌时,客户端将在接收到的ID令牌中获取所有范围请求的userinfo声明,从而消除了调用userinfo的需要。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74490291

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档