mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(core): add hasPassword field to custom JWT user context (#6096)
This commit is contained in:
parent
f2c7799ee6
commit
b52609a1ed
6 changed files with 44 additions and 10 deletions
7
.changeset/sharp-cooks-explain.md
Normal file
7
.changeset/sharp-cooks-explain.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
"@logto/console": minor
|
||||
"@logto/schemas": minor
|
||||
"@logto/core": minor
|
||||
---
|
||||
|
||||
add `hasPassword` to custom JWT user context
|
|
@ -182,6 +182,7 @@ export const defaultClientCredentialsPayload: ClientCredentialsPayload = {
|
|||
|
||||
const defaultUserContext: Partial<JwtCustomizerUserContext> = {
|
||||
id: '123',
|
||||
hasPassword: false,
|
||||
username: 'foo',
|
||||
primaryEmail: 'foo@logto.io',
|
||||
primaryPhone: '+1234567890',
|
||||
|
|
|
@ -87,6 +87,7 @@ export class JwtCustomizerLibrary {
|
|||
await this.queries.organizations.relations.users.getOrganizationsByUserId(userId);
|
||||
const userContext = {
|
||||
...pick(user, ...userInfoSelectFields),
|
||||
hasPassword: Boolean(user.passwordEncrypted),
|
||||
ssoIdentities: fullSsoIdentities.map(pickState('issuer', 'identityId', 'detail')),
|
||||
mfaVerificationFactors: deduplicate(user.mfaVerifications.map(({ type }) => type)),
|
||||
roles: roles.map((role) => {
|
||||
|
|
|
@ -55,8 +55,8 @@ export const accessTokenJwtCustomizerPayload = {
|
|||
};
|
||||
|
||||
export const accessTokenSampleScript = `const getCustomJwtClaims = async ({ token, context, environmentVariables }) => {
|
||||
return { user_id: context?.user?.id ?? 'unknown' };
|
||||
}`;
|
||||
return { user_id: context?.user?.id ?? 'unknown', hasPassword: context?.user?.hasPassword };
|
||||
};`;
|
||||
|
||||
export const clientCredentialsSampleScript = `const getCustomJwtClaims = async ({ token, context, environmentVariables }) => {
|
||||
return { ...environmentVariables };
|
||||
|
|
|
@ -125,6 +125,8 @@ describe('get access token', () => {
|
|||
testApiScopeNames.join(' ')
|
||||
);
|
||||
expect(getAccessTokenPayload(accessToken)).toHaveProperty('user_id', guestUserId);
|
||||
// The guest user has password.
|
||||
expect(getAccessTokenPayload(accessToken)).toHaveProperty('hasPassword', true);
|
||||
|
||||
await deleteJwtCustomizer('access-token');
|
||||
});
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import { jsonObjectGuard } from '@logto/connector-kit';
|
||||
import { z } from 'zod';
|
||||
import { type ZodType, z } from 'zod';
|
||||
|
||||
import { Organizations, Roles, UserSsoIdentities } from '../../db-entries/index.js';
|
||||
import { mfaFactorsGuard } from '../../foundations/index.js';
|
||||
import { scopeResponseGuard } from '../scope.js';
|
||||
import { userInfoGuard } from '../user.js';
|
||||
import {
|
||||
Organizations,
|
||||
type Organization,
|
||||
type Role,
|
||||
Roles,
|
||||
UserSsoIdentities,
|
||||
type UserSsoIdentity,
|
||||
} from '../../db-entries/index.js';
|
||||
import { mfaFactorsGuard, type MfaFactors } from '../../foundations/index.js';
|
||||
import { scopeResponseGuard, type ScopeResponse } from '../scope.js';
|
||||
import { userInfoGuard, type UserInfo } from '../user.js';
|
||||
|
||||
import { accessTokenPayloadGuard, clientCredentialsPayloadGuard } from './oidc-provider.js';
|
||||
|
||||
|
@ -19,7 +26,25 @@ export enum LogtoJwtTokenKeyType {
|
|||
ClientCredentials = 'client-credentials',
|
||||
}
|
||||
|
||||
export type JwtCustomizerUserContext = UserInfo & {
|
||||
hasPassword: boolean;
|
||||
ssoIdentities: Array<Pick<UserSsoIdentity, 'issuer' | 'identityId' | 'detail'>>;
|
||||
mfaVerificationFactors: MfaFactors;
|
||||
roles: Array<
|
||||
Pick<Role, 'id' | 'name' | 'description'> & {
|
||||
scopes: Array<Pick<ScopeResponse, 'id' | 'name' | 'description' | 'resourceId' | 'resource'>>;
|
||||
}
|
||||
>;
|
||||
organizations: Array<Pick<Organization, 'id' | 'name' | 'description'>>;
|
||||
organizationRoles: Array<{
|
||||
organizationId: string;
|
||||
roleId: string;
|
||||
roleName: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export const jwtCustomizerUserContextGuard = userInfoGuard.extend({
|
||||
hasPassword: z.boolean(),
|
||||
ssoIdentities: UserSsoIdentities.guard
|
||||
.pick({ issuer: true, identityId: true, detail: true })
|
||||
.array(),
|
||||
|
@ -40,9 +65,7 @@ export const jwtCustomizerUserContextGuard = userInfoGuard.extend({
|
|||
roleName: z.string(),
|
||||
})
|
||||
.array(),
|
||||
});
|
||||
|
||||
export type JwtCustomizerUserContext = z.infer<typeof jwtCustomizerUserContextGuard>;
|
||||
}) satisfies ZodType<JwtCustomizerUserContext>;
|
||||
|
||||
export const accessTokenJwtCustomizerGuard = jwtCustomizerGuard
|
||||
.extend({
|
||||
|
|
Loading…
Reference in a new issue