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

fix(core): remove grant id of token exchange (#6497)

This commit is contained in:
wangsijie 2024-08-22 11:45:50 +08:00 committed by GitHub
parent f0bbc2a1f4
commit 06f98634c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 22 additions and 10 deletions

View file

@ -10,6 +10,7 @@ import {
import { generateStandardId } from '@logto/shared'; import { generateStandardId } from '@logto/shared';
import { conditional, trySafe } from '@silverhand/essentials'; import { conditional, trySafe } from '@silverhand/essentials';
import { type KoaContextWithOIDC, type UnknownObject } from 'oidc-provider'; import { type KoaContextWithOIDC, type UnknownObject } from 'oidc-provider';
import { z } from 'zod';
import { EnvSet } from '#src/env-set/index.js'; import { EnvSet } from '#src/env-set/index.js';
import { type CloudConnectionLibrary } from '#src/libraries/cloud-connection.js'; import { type CloudConnectionLibrary } from '#src/libraries/cloud-connection.js';
@ -142,10 +143,17 @@ export const getExtraTokenClaimsForJwtCustomization = async (
(await libraries.jwtCustomizers.getUserContext(token.accountId)) (await libraries.jwtCustomizers.getUserContext(token.accountId))
); );
const subjectTokenResult = z
.object({
subjectTokenId: z.string(),
})
.safeParse(token.extra);
const subjectToken = const subjectToken =
isTokenClientCredentials || token.gty !== GrantType.TokenExchange isTokenClientCredentials || token.gty !== GrantType.TokenExchange
? undefined ? undefined
: await trySafe(async () => queries.subjectTokens.findSubjectToken(token.grantId)); : subjectTokenResult.success
? await queries.subjectTokens.findSubjectToken(subjectTokenResult.data.subjectTokenId)
: undefined;
const payload: CustomJwtFetcher = { const payload: CustomJwtFetcher = {
script, script,

View file

@ -1,4 +1,3 @@
import { generateStandardShortId } from '@logto/shared';
import { trySafe } from '@silverhand/essentials'; import { trySafe } from '@silverhand/essentials';
import { errors } from 'oidc-provider'; import { errors } from 'oidc-provider';
@ -13,7 +12,7 @@ export const validateSubjectToken = async (
queries: Queries, queries: Queries,
subjectToken: string, subjectToken: string,
type: string type: string
): Promise<{ userId: string; grantId: string; subjectTokenId?: string }> => { ): Promise<{ userId: string; subjectTokenId?: string }> => {
const { const {
subjectTokens: { findSubjectToken }, subjectTokens: { findSubjectToken },
personalAccessTokens: { findByValue }, personalAccessTokens: { findByValue },
@ -27,7 +26,6 @@ export const validateSubjectToken = async (
return { return {
userId: token.userId, userId: token.userId,
grantId: token.id,
subjectTokenId: token.id, subjectTokenId: token.id,
}; };
} }
@ -39,7 +37,7 @@ export const validateSubjectToken = async (
new InvalidGrant('subject token is expired') new InvalidGrant('subject token is expired')
); );
return { userId: token.userId, grantId: generateStandardShortId() }; return { userId: token.userId };
} }
throw new InvalidGrant('unsupported subject token type'); throw new InvalidGrant('unsupported subject token type');
}; };

View file

@ -180,7 +180,6 @@ describe('token exchange', () => {
expect(value).toMatchObject({ expect(value).toMatchObject({
accountId, accountId,
clientId, clientId,
grantId: subjectTokenId,
gty: 'urn:ietf:params:oauth:grant-type:token-exchange', gty: 'urn:ietf:params:oauth:grant-type:token-exchange',
}); });
}); });
@ -244,7 +243,6 @@ describe('token exchange', () => {
expect(value).toMatchObject({ expect(value).toMatchObject({
accountId, accountId,
clientId, clientId,
grantId: subjectTokenId,
aud: 'urn:logto:organization:some_org_id', aud: 'urn:logto:organization:some_org_id',
}); });
}); });

View file

@ -82,7 +82,7 @@ export const buildHandler: (
scopes: oidcScopes, scopes: oidcScopes,
} = providerInstance.configuration(); } = providerInstance.configuration();
const { userId, grantId, subjectTokenId } = await validateSubjectToken( const { userId, subjectTokenId } = await validateSubjectToken(
queries, queries,
String(params.subject_token), String(params.subject_token),
String(params.subject_token_type) String(params.subject_token_type)
@ -103,9 +103,14 @@ export const buildHandler: (
clientId: client.clientId, clientId: client.clientId,
gty: GrantType.TokenExchange, gty: GrantType.TokenExchange,
client, client,
grantId, // The token exchange grant type does not have a grant ID or grant object,
// so we use an empty string here.
grantId: '',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
scope: undefined!, scope: undefined!,
extra: {
...(subjectTokenId ? { subjectTokenId } : {}),
},
}); });
await handleDPoP(ctx, accessToken); await handleDPoP(ctx, accessToken);
@ -184,7 +189,10 @@ export const buildHandler: (
// @see https://github.com/panva/node-oidc-provider/blob/main/lib/models/formats/jwt.js#L118 // @see https://github.com/panva/node-oidc-provider/blob/main/lib/models/formats/jwt.js#L118
// We save the `act` data in the `extra` field temporarily, // We save the `act` data in the `extra` field temporarily,
// so that we can get this context it in the `extraTokenClaims` function and add it to the JWT. // so that we can get this context it in the `extraTokenClaims` function and add it to the JWT.
accessToken.extra = { act: { sub: actorId } } satisfies TokenExchangeAct; accessToken.extra = {
...accessToken.extra,
...({ act: { sub: actorId } } satisfies TokenExchangeAct),
};
} }
ctx.oidc.entity('AccessToken', accessToken); ctx.oidc.entity('AccessToken', accessToken);