i have some issues getting the UserInfo endpoint working using JWT AccessTokens, it works fine with default settings when commenting out the resourceIndicators
section.
I can get the access token using PostMan without issues, but when posting on the UserInfo (/me) endpoint the Bearer AccessToken, i got an invalid_token
error.
here is my code:
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}.`)
})
I tried different configurations without success, the generated JWT AccessToken looks fine to me (see bellow), but i'm unable to query the UserInfo endpoint with it.
{
"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"
}
Thanks in advance.