mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-11 04:19:31 +00:00
feat(sso): support disabling setting email verified from a provider (#3551)
* feat: support disabling setting email verified * Update docs/content/docs/plugins/sso.mdx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: update account handling in SSO to support trusted providers * default to not setting email verified * docs: update documentation * add attribute map --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
generateState,
|
||||
type Account,
|
||||
type BetterAuthPlugin,
|
||||
type OAuth2Tokens,
|
||||
type Session,
|
||||
@@ -148,6 +149,11 @@ export interface SSOOptions {
|
||||
* @default 10
|
||||
*/
|
||||
providersLimit?: number | ((user: User) => Promise<number> | number);
|
||||
/**
|
||||
* Trust the email verified flag from the provider.
|
||||
* @default false
|
||||
*/
|
||||
trustEmailVerified?: boolean;
|
||||
}
|
||||
|
||||
export const sso = (options?: SSOOptions) => {
|
||||
@@ -1093,7 +1099,9 @@ export const sso = (options?: SSOOptions) => {
|
||||
),
|
||||
id: idToken[mapping.id || "sub"],
|
||||
email: idToken[mapping.email || "email"],
|
||||
emailVerified: idToken[mapping.emailVerified || "email_verified"],
|
||||
emailVerified: options?.trustEmailVerified
|
||||
? idToken[mapping.emailVerified || "email_verified"]
|
||||
: false,
|
||||
name: idToken[mapping.name || "name"],
|
||||
image: idToken[mapping.image || "picture"],
|
||||
} as {
|
||||
@@ -1149,7 +1157,9 @@ export const sso = (options?: SSOOptions) => {
|
||||
name: userInfo.name || userInfo.email,
|
||||
id: userInfo.id,
|
||||
image: userInfo.image,
|
||||
emailVerified: userInfo.emailVerified || false,
|
||||
emailVerified: options?.trustEmailVerified
|
||||
? userInfo.emailVerified || false
|
||||
: false,
|
||||
},
|
||||
account: {
|
||||
idToken: tokenResponse.idToken,
|
||||
@@ -1325,6 +1335,9 @@ export const sso = (options?: SSOOptions) => {
|
||||
.filter(Boolean)
|
||||
.join(" ") || parsedResponse.extract.attributes?.displayName,
|
||||
attributes: parsedResponse.extract.attributes,
|
||||
emailVerified: options?.trustEmailVerified
|
||||
? ((attributes?.[mapping.emailVerified] || false) as boolean)
|
||||
: false,
|
||||
};
|
||||
|
||||
let user: User;
|
||||
@@ -1340,6 +1353,37 @@ export const sso = (options?: SSOOptions) => {
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
const accounts = await ctx.context.adapter.findOne<Account>({
|
||||
model: "account",
|
||||
where: [
|
||||
{ field: "userId", value: existingUser.id },
|
||||
{ field: "providerId", value: provider.providerId },
|
||||
{ field: "accountId", value: userInfo.id },
|
||||
],
|
||||
});
|
||||
if (!accounts) {
|
||||
const isTrustedProvider =
|
||||
ctx.context.options.account?.accountLinking?.trustedProviders?.includes(
|
||||
provider.providerId,
|
||||
);
|
||||
if (!isTrustedProvider) {
|
||||
throw ctx.redirect(
|
||||
`${parsedSamlConfig.callbackUrl}?error=account_not_found`,
|
||||
);
|
||||
}
|
||||
await ctx.context.adapter.create<Account>({
|
||||
model: "account",
|
||||
data: {
|
||||
userId: existingUser.id,
|
||||
providerId: provider.providerId,
|
||||
accountId: userInfo.id,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
accessToken: "",
|
||||
refreshToken: "",
|
||||
},
|
||||
});
|
||||
}
|
||||
user = existingUser;
|
||||
} else {
|
||||
user = await ctx.context.adapter.create({
|
||||
@@ -1347,7 +1391,26 @@ export const sso = (options?: SSOOptions) => {
|
||||
data: {
|
||||
email: userInfo.email,
|
||||
name: userInfo.name,
|
||||
emailVerified: true,
|
||||
emailVerified: options?.trustEmailVerified
|
||||
? userInfo.emailVerified || false
|
||||
: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
await ctx.context.adapter.create<Account>({
|
||||
model: "account",
|
||||
data: {
|
||||
userId: user.id,
|
||||
providerId: provider.providerId,
|
||||
accountId: userInfo.id,
|
||||
accessToken: "",
|
||||
refreshToken: "",
|
||||
accessTokenExpiresAt: new Date(),
|
||||
refreshTokenExpiresAt: new Date(),
|
||||
scope: "",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user