UNPKG

better-auth

Version:

The most comprehensive authentication framework for TypeScript.

1 lines • 11.2 kB
{"version":3,"file":"link-account.mjs","names":["e: any"],"sources":["../../src/oauth2/link-account.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"@better-auth/core\";\nimport { isDevelopment, logger } from \"@better-auth/core/env\";\nimport { APIError, createEmailVerificationToken } from \"../api\";\nimport { setAccountCookie } from \"../cookies/session-store\";\nimport type { Account, User } from \"../types\";\nimport { setTokenUtil } from \"./utils\";\n\nexport async function handleOAuthUserInfo(\n\tc: GenericEndpointContext,\n\topts: {\n\t\tuserInfo: Omit<User, \"createdAt\" | \"updatedAt\">;\n\t\taccount: Omit<Account, \"id\" | \"userId\" | \"createdAt\" | \"updatedAt\">;\n\t\tcallbackURL?: string | undefined;\n\t\tdisableSignUp?: boolean | undefined;\n\t\toverrideUserInfo?: boolean | undefined;\n\t\tisTrustedProvider?: boolean | undefined;\n\t},\n) {\n\tconst { userInfo, account, callbackURL, disableSignUp, overrideUserInfo } =\n\t\topts;\n\tconst dbUser = await c.context.internalAdapter\n\t\t.findOAuthUser(\n\t\t\tuserInfo.email.toLowerCase(),\n\t\t\taccount.accountId,\n\t\t\taccount.providerId,\n\t\t)\n\t\t.catch((e) => {\n\t\t\tlogger.error(\n\t\t\t\t\"Better auth was unable to query your database.\\nError: \",\n\t\t\t\te,\n\t\t\t);\n\t\t\tconst errorURL =\n\t\t\t\tc.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`;\n\t\t\tthrow c.redirect(`${errorURL}?error=internal_server_error`);\n\t\t});\n\tlet user = dbUser?.user;\n\tlet isRegister = !user;\n\n\tif (dbUser) {\n\t\tconst hasBeenLinked = dbUser.accounts.find(\n\t\t\t(a) =>\n\t\t\t\ta.providerId === account.providerId &&\n\t\t\t\ta.accountId === account.accountId,\n\t\t);\n\t\tif (!hasBeenLinked) {\n\t\t\tconst trustedProviders =\n\t\t\t\tc.context.options.account?.accountLinking?.trustedProviders;\n\t\t\tconst isTrustedProvider =\n\t\t\t\topts.isTrustedProvider ||\n\t\t\t\ttrustedProviders?.includes(account.providerId as \"apple\");\n\t\t\tif (\n\t\t\t\t(!isTrustedProvider && !userInfo.emailVerified) ||\n\t\t\t\tc.context.options.account?.accountLinking?.enabled === false\n\t\t\t) {\n\t\t\t\tif (isDevelopment()) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Better Auth see https://www.better-auth.com/docs/concepts/users-accounts#account-linking.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\terror: \"account not linked\",\n\t\t\t\t\tdata: null,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait c.context.internalAdapter.linkAccount({\n\t\t\t\t\tproviderId: account.providerId,\n\t\t\t\t\taccountId: userInfo.id.toString(),\n\t\t\t\t\tuserId: dbUser.user.id,\n\t\t\t\t\taccessToken: await setTokenUtil(account.accessToken, c.context),\n\t\t\t\t\trefreshToken: await setTokenUtil(account.refreshToken, c.context),\n\t\t\t\t\tidToken: account.idToken,\n\t\t\t\t\taccessTokenExpiresAt: account.accessTokenExpiresAt,\n\t\t\t\t\trefreshTokenExpiresAt: account.refreshTokenExpiresAt,\n\t\t\t\t\tscope: account.scope,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(\"Unable to link account\", e);\n\t\t\t\treturn {\n\t\t\t\t\terror: \"unable to link account\",\n\t\t\t\t\tdata: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tuserInfo.emailVerified &&\n\t\t\t\t!dbUser.user.emailVerified &&\n\t\t\t\tuserInfo.email.toLowerCase() === dbUser.user.email\n\t\t\t) {\n\t\t\t\tawait c.context.internalAdapter.updateUser(dbUser.user.id, {\n\t\t\t\t\temailVerified: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif (c.context.options.account?.updateAccountOnSignIn !== false) {\n\t\t\t\tconst updateData = Object.fromEntries(\n\t\t\t\t\tObject.entries({\n\t\t\t\t\t\tidToken: account.idToken,\n\t\t\t\t\t\taccessToken: await setTokenUtil(account.accessToken, c.context),\n\t\t\t\t\t\trefreshToken: await setTokenUtil(account.refreshToken, c.context),\n\t\t\t\t\t\taccessTokenExpiresAt: account.accessTokenExpiresAt,\n\t\t\t\t\t\trefreshTokenExpiresAt: account.refreshTokenExpiresAt,\n\t\t\t\t\t\tscope: account.scope,\n\t\t\t\t\t}).filter(([_, value]) => value !== undefined),\n\t\t\t\t);\n\t\t\t\tif (c.context.options.account?.storeAccountCookie) {\n\t\t\t\t\tawait setAccountCookie(c, {\n\t\t\t\t\t\t...account,\n\t\t\t\t\t\t...updateData,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (Object.keys(updateData).length > 0) {\n\t\t\t\t\tawait c.context.internalAdapter.updateAccount(\n\t\t\t\t\t\thasBeenLinked.id,\n\t\t\t\t\t\tupdateData,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tuserInfo.emailVerified &&\n\t\t\t\t!dbUser.user.emailVerified &&\n\t\t\t\tuserInfo.email.toLowerCase() === dbUser.user.email\n\t\t\t) {\n\t\t\t\tawait c.context.internalAdapter.updateUser(dbUser.user.id, {\n\t\t\t\t\temailVerified: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif (overrideUserInfo) {\n\t\t\tconst { id: _, ...restUserInfo } = userInfo;\n\t\t\t// update user info from the provider if overrideUserInfo is true\n\t\t\tuser = await c.context.internalAdapter.updateUser(dbUser.user.id, {\n\t\t\t\t...restUserInfo,\n\t\t\t\temail: userInfo.email.toLowerCase(),\n\t\t\t\temailVerified:\n\t\t\t\t\tuserInfo.email.toLowerCase() === dbUser.user.email\n\t\t\t\t\t\t? dbUser.user.emailVerified || userInfo.emailVerified\n\t\t\t\t\t\t: userInfo.emailVerified,\n\t\t\t});\n\t\t}\n\t} else {\n\t\tif (disableSignUp) {\n\t\t\treturn {\n\t\t\t\terror: \"signup disabled\",\n\t\t\t\tdata: null,\n\t\t\t\tisRegister: false,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\tconst { id: _, ...restUserInfo } = userInfo;\n\t\t\tconst accountData = {\n\t\t\t\taccessToken: await setTokenUtil(account.accessToken, c.context),\n\t\t\t\trefreshToken: await setTokenUtil(account.refreshToken, c.context),\n\t\t\t\tidToken: account.idToken,\n\t\t\t\taccessTokenExpiresAt: account.accessTokenExpiresAt,\n\t\t\t\trefreshTokenExpiresAt: account.refreshTokenExpiresAt,\n\t\t\t\tscope: account.scope,\n\t\t\t\tproviderId: account.providerId,\n\t\t\t\taccountId: userInfo.id.toString(),\n\t\t\t};\n\t\t\tconst { user: createdUser, account: createdAccount } =\n\t\t\t\tawait c.context.internalAdapter.createOAuthUser(\n\t\t\t\t\t{\n\t\t\t\t\t\t...restUserInfo,\n\t\t\t\t\t\temail: userInfo.email.toLowerCase(),\n\t\t\t\t\t},\n\t\t\t\t\taccountData,\n\t\t\t\t);\n\t\t\tuser = createdUser;\n\t\t\tif (c.context.options.account?.storeAccountCookie) {\n\t\t\t\tawait setAccountCookie(c, createdAccount);\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!userInfo.emailVerified &&\n\t\t\t\tuser &&\n\t\t\t\tc.context.options.emailVerification?.sendOnSignUp &&\n\t\t\t\tc.context.options.emailVerification?.sendVerificationEmail\n\t\t\t) {\n\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\tc.context.secret,\n\t\t\t\t\tuser.email,\n\t\t\t\t\tundefined,\n\t\t\t\t\tc.context.options.emailVerification?.expiresIn,\n\t\t\t\t);\n\t\t\t\tconst url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\t\t\t\tawait c.context.runInBackgroundOrAwait(\n\t\t\t\t\tc.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tc.request,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (e: any) {\n\t\t\tlogger.error(e);\n\t\t\tif (e instanceof APIError) {\n\t\t\t\treturn {\n\t\t\t\t\terror: e.message,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tisRegister: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\terror: \"unable to create user\",\n\t\t\t\tdata: null,\n\t\t\t\tisRegister: false,\n\t\t\t};\n\t\t}\n\t}\n\tif (!user) {\n\t\treturn {\n\t\t\terror: \"unable to create user\",\n\t\t\tdata: null,\n\t\t\tisRegister: false,\n\t\t};\n\t}\n\n\tconst session = await c.context.internalAdapter.createSession(user.id);\n\tif (!session) {\n\t\treturn {\n\t\t\terror: \"unable to create session\",\n\t\t\tdata: null,\n\t\t\tisRegister: false,\n\t\t};\n\t}\n\n\treturn {\n\t\tdata: {\n\t\t\tsession,\n\t\t\tuser,\n\t\t},\n\t\terror: null,\n\t\tisRegister,\n\t};\n}\n"],"mappings":"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"}