0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-27 21:39:16 -05:00

feat(core): handle oidc scopes for token exchange (#6147)

* feat(core,schemas): token exchange grant

* feat(core): third-party applications are not allowed for token exchange

* feat(core,schemas): token exchange grant

* feat(core): organization token for token exchange flow

* feat(core): handle oidc scopes for token exchange
This commit is contained in:
wangsijie 2024-07-03 16:32:57 +08:00 committed by GitHub
parent de9ee8962a
commit 504f5b2a99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 3 deletions

View file

@ -73,6 +73,7 @@ export const buildHandler: (
const providerInstance = instance(provider);
const {
features: { userinfo, resourceIndicators },
scopes: oidcScopes,
} = providerInstance.configuration();
const subjectToken = await trySafe(async () => findSubjectToken(String(params.subject_token)));
@ -186,9 +187,15 @@ export const buildHandler: (
.filter(Set.prototype.has.bind(accessToken.resourceServer.scopes))
.join(' ');
} else {
// TODO: (LOG-9166) Check claims and scopes
accessToken.claims = ctx.oidc.claims;
accessToken.scope = Array.from(scope).join(' ');
// Filter scopes from `oidcScopes`,
// in other grants, this is done by `Grant` class
// See https://github.com/panva/node-oidc-provider/blob/0c569cf5c36dd5faa105fb931a43b2e587530def/lib/helpers/oidc_context.js#L159
accessToken.scope = Array.from(scope)
// Wrong typing for oidc-provider, `oidcScopes` is actully a Set,
// wrap it with `new Set` to make it work
.filter((name) => new Set(oidcScopes).has(name))
.join(' ');
}
/* eslint-enable @silverhand/fp/no-mutation, @typescript-eslint/no-unsafe-assignment */

View file

@ -1,4 +1,4 @@
import { buildOrganizationUrn } from '@logto/core-kit';
import { UserScope, buildOrganizationUrn } from '@logto/core-kit';
import { decodeAccessToken } from '@logto/js';
import { ApplicationType, GrantType, MfaFactor } from '@logto/schemas';
import { formUrlEncodedHeaders } from '@logto/shared';
@ -137,6 +137,28 @@ describe('Token Exchange', () => {
await deleteApplication(thirdPartyApplication.id);
});
it('should filter out non-oidc scopes', async () => {
const { subjectToken } = await createSubjectToken(userId);
const body = await oidcApi
.post('token', {
headers: formUrlEncodedHeaders,
body: new URLSearchParams({
client_id: applicationId,
grant_type: GrantType.TokenExchange,
subject_token: subjectToken,
subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
scope: [UserScope.Profile, 'non-oidc-scope'].join(' '),
}),
})
.json();
expect(body).toHaveProperty('access_token');
expect(body).toHaveProperty('token_type', 'Bearer');
expect(body).toHaveProperty('expires_in');
expect(body).toHaveProperty('scope', UserScope.Profile);
});
});
describe('get access token for organization', () => {