mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 12:27:44 +00:00
feat(oidc-provider): add client to getAdditionalUserInfoClaim callback (#3790)
* feat: add oidc Client to getAdditionalUserInfoClaim * address cubic comments * run format
This commit is contained in:
@@ -246,7 +246,7 @@ The UserInfo endpoint returns different claims based on the scopes that were gra
|
|||||||
- With `profile` scope: Returns name, picture, given_name, family_name
|
- With `profile` scope: Returns name, picture, given_name, family_name
|
||||||
- With `email` scope: Returns email and email_verified
|
- With `email` scope: Returns email and email_verified
|
||||||
|
|
||||||
The `getAdditionalUserInfoClaim` function receives the user object and the requested scopes array, allowing you to conditionally include claims based on the scopes granted during authorization. These additional claims will be included in both the UserInfo endpoint response and the ID token.
|
The `getAdditionalUserInfoClaim` function receives the user object, requested scopes array, and the client, allowing you to conditionally include claims based on the scopes granted during authorization. These additional claims will be included in both the UserInfo endpoint response and the ID token.
|
||||||
|
|
||||||
### Consent Screen
|
### Consent Screen
|
||||||
|
|
||||||
@@ -561,6 +561,6 @@ Table Name: `oauthConsent`
|
|||||||
|
|
||||||
**trustedClients**: `(Client & { skipConsent?: boolean })[]` - Array of trusted clients that are configured directly in the provider options. These clients bypass database lookups and can optionally skip consent screens.
|
**trustedClients**: `(Client & { skipConsent?: boolean })[]` - Array of trusted clients that are configured directly in the provider options. These clients bypass database lookups and can optionally skip consent screens.
|
||||||
|
|
||||||
**getAdditionalUserInfoClaim**: `(user: User, scopes: string[]) => Record<string, any>` - Function to get additional user info claims.
|
**getAdditionalUserInfoClaim**: `(user: User, scopes: string[], client: Client) => Record<string, any>` - Function to get additional user info claims.
|
||||||
|
|
||||||
**useJWTPlugin**: `boolean` - When `true`, ID tokens are signed using the JWT plugin's asymmetric keys. When `false` (default), ID tokens are signed with HMAC-SHA256 using the application secret.
|
**useJWTPlugin**: `boolean` - When `true`, ID tokens are signed using the JWT plugin's asymmetric keys. When `false` (default), ID tokens are signed with HMAC-SHA256 using the application secret.
|
||||||
@@ -570,7 +570,11 @@ export const mcp = (options: MCPOptions) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const additionalUserClaims = opts.getAdditionalUserInfoClaim
|
const additionalUserClaims = opts.getAdditionalUserInfoClaim
|
||||||
? opts.getAdditionalUserInfoClaim(user, requestedScopes)
|
? await opts.getAdditionalUserInfoClaim(
|
||||||
|
user,
|
||||||
|
requestedScopes,
|
||||||
|
client,
|
||||||
|
)
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const idToken = await new SignJWT({
|
const idToken = await new SignJWT({
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ describe("mcp", async () => {
|
|||||||
loginPage: "/login",
|
loginPage: "/login",
|
||||||
requirePKCE: true,
|
requirePKCE: true,
|
||||||
|
|
||||||
getAdditionalUserInfoClaim(user, scopes) {
|
getAdditionalUserInfoClaim(user, scopes, client) {
|
||||||
return {
|
return {
|
||||||
custom: "custom value",
|
custom: "custom value",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
|||||||
@@ -754,7 +754,11 @@ export const oidcProvider = (options: OIDCOptions) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const additionalUserClaims = options.getAdditionalUserInfoClaim
|
const additionalUserClaims = options.getAdditionalUserInfoClaim
|
||||||
? await options.getAdditionalUserInfoClaim(user, requestedScopes)
|
? await options.getAdditionalUserInfoClaim(
|
||||||
|
user,
|
||||||
|
requestedScopes,
|
||||||
|
client,
|
||||||
|
)
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -958,6 +962,18 @@ export const oidcProvider = (options: OIDCOptions) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const client = await getClient(
|
||||||
|
accessToken.clientId,
|
||||||
|
ctx.context.adapter,
|
||||||
|
trustedClients,
|
||||||
|
);
|
||||||
|
if (!client) {
|
||||||
|
throw new APIError("UNAUTHORIZED", {
|
||||||
|
error_description: "client not found",
|
||||||
|
error: "invalid_token",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const user = await ctx.context.internalAdapter.findUserById(
|
const user = await ctx.context.internalAdapter.findUserById(
|
||||||
accessToken.userId,
|
accessToken.userId,
|
||||||
);
|
);
|
||||||
@@ -986,7 +1002,11 @@ export const oidcProvider = (options: OIDCOptions) => {
|
|||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
const userClaims = options.getAdditionalUserInfoClaim
|
const userClaims = options.getAdditionalUserInfoClaim
|
||||||
? await options.getAdditionalUserInfoClaim(user, requestedScopes)
|
? await options.getAdditionalUserInfoClaim(
|
||||||
|
user,
|
||||||
|
requestedScopes,
|
||||||
|
client,
|
||||||
|
)
|
||||||
: baseUserClaims;
|
: baseUserClaims;
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
...baseUserClaims,
|
...baseUserClaims,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe("oidc", async () => {
|
|||||||
loginPage: "/login",
|
loginPage: "/login",
|
||||||
consentPage: "/oauth2/authorize",
|
consentPage: "/oauth2/authorize",
|
||||||
requirePKCE: true,
|
requirePKCE: true,
|
||||||
getAdditionalUserInfoClaim(user, scopes) {
|
getAdditionalUserInfoClaim(user, scopes, client) {
|
||||||
return {
|
return {
|
||||||
custom: "custom value",
|
custom: "custom value",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@@ -376,7 +376,7 @@ describe("oidc storage", async () => {
|
|||||||
loginPage: "/login",
|
loginPage: "/login",
|
||||||
consentPage: "/oauth2/authorize",
|
consentPage: "/oauth2/authorize",
|
||||||
requirePKCE: true,
|
requirePKCE: true,
|
||||||
getAdditionalUserInfoClaim(user, scopes) {
|
getAdditionalUserInfoClaim(user, scopes, client) {
|
||||||
return {
|
return {
|
||||||
custom: "custom value",
|
custom: "custom value",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@@ -535,7 +535,7 @@ describe("oidc-jwt", async () => {
|
|||||||
loginPage: "/login",
|
loginPage: "/login",
|
||||||
consentPage: "/oauth2/authorize",
|
consentPage: "/oauth2/authorize",
|
||||||
requirePKCE: true,
|
requirePKCE: true,
|
||||||
getAdditionalUserInfoClaim(user, scopes) {
|
getAdditionalUserInfoClaim(user, scopes, client) {
|
||||||
return {
|
return {
|
||||||
custom: "custom value",
|
custom: "custom value",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
|||||||
@@ -115,11 +115,13 @@ export interface OIDCOptions {
|
|||||||
*
|
*
|
||||||
* @param user - The user object.
|
* @param user - The user object.
|
||||||
* @param scopes - The scopes that the client requested.
|
* @param scopes - The scopes that the client requested.
|
||||||
|
* @param client - The client object.
|
||||||
* @returns The user info claim.
|
* @returns The user info claim.
|
||||||
*/
|
*/
|
||||||
getAdditionalUserInfoClaim?: (
|
getAdditionalUserInfoClaim?: (
|
||||||
user: User & Record<string, any>,
|
user: User & Record<string, any>,
|
||||||
scopes: string[],
|
scopes: string[],
|
||||||
|
client: Client,
|
||||||
) => Record<string, any> | Promise<Record<string, any>>;
|
) => Record<string, any> | Promise<Record<string, any>>;
|
||||||
/**
|
/**
|
||||||
* Trusted clients that are configured directly in the provider options.
|
* Trusted clients that are configured directly in the provider options.
|
||||||
|
|||||||
Reference in New Issue
Block a user