diff --git a/.env.example b/.env.example index a07419aaa..19f056cd8 100644 --- a/.env.example +++ b/.env.example @@ -16,6 +16,10 @@ NEXT_PRIVATE_GOOGLE_CLIENT_SECRET="" NEXT_PRIVATE_OIDC_WELL_KNOWN="" NEXT_PRIVATE_OIDC_CLIENT_ID="" NEXT_PRIVATE_OIDC_CLIENT_SECRET="" +# This can be used to still allow signups for OIDC connections +# when signup is disabled via `NEXT_PUBLIC_DISABLE_SIGNUP` +NEXT_PRIVATE_OIDC_ALLOW_SIGNUP="" +NEXT_PRIVATE_OIDC_SKIP_VERIFY="" # [[URLS]] NEXT_PUBLIC_WEBAPP_URL="http://localhost:3000" diff --git a/apps/web/process-env.d.ts b/apps/web/process-env.d.ts index 63a341060..8bdfa41f9 100644 --- a/apps/web/process-env.d.ts +++ b/apps/web/process-env.d.ts @@ -16,5 +16,7 @@ declare namespace NodeJS { NEXT_PRIVATE_OIDC_WELL_KNOWN: string; NEXT_PRIVATE_OIDC_CLIENT_ID: string; NEXT_PRIVATE_OIDC_CLIENT_SECRET: string; + NEXT_PRIVATE_OIDC_ALLOW_SIGNUP?: string; + NEXT_PRIVATE_OIDC_SKIP_VERIFY?: string; } } diff --git a/apps/web/src/pages/api/auth/[...nextauth].ts b/apps/web/src/pages/api/auth/[...nextauth].ts index 31f6e9ea3..44c509c62 100644 --- a/apps/web/src/pages/api/auth/[...nextauth].ts +++ b/apps/web/src/pages/api/auth/[...nextauth].ts @@ -60,13 +60,23 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) { }, }); }, - linkAccount: async ({ user }) => { + linkAccount: async ({ user, account, profile }) => { const userId = typeof user.id === 'string' ? parseInt(user.id) : user.id; - if (isNaN(userId)) { + if (Number.isNaN(userId)) { return; } + // If the user is linking an OIDC account and the email verified date is set then update it in the db. + if (account.provider === 'oidc' && profile.emailVerified !== null) { + await prisma.user.update({ + where: { id: userId }, + data: { + emailVerified: profile.emailVerified, + }, + }); + } + await prisma.userSecurityAuditLog.create({ data: { userId, diff --git a/packages/lib/next-auth/auth-options.ts b/packages/lib/next-auth/auth-options.ts index b0d27589c..fa4413115 100644 --- a/packages/lib/next-auth/auth-options.ts +++ b/packages/lib/next-auth/auth-options.ts @@ -161,7 +161,10 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = { id: profile.sub, email: profile.email || profile.preferred_username, name: profile.name || `${profile.given_name} ${profile.family_name}`.trim(), - emailVerified: profile.email_verified ? new Date().toISOString() : null, + emailVerified: + process.env.NEXT_PRIVATE_OIDC_SKIP_VERIFY === 'true' || profile.email_verified + ? new Date().toISOString() + : null, }; }, }, @@ -361,6 +364,12 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = { }, async signIn({ user }) { + // This statement appears above so we can stil allow `oidc` connections + // while other signups are disabled. + if (env('NEXT_PRIVATE_OIDC_ALLOW_SIGNUP') === 'true') { + return true; + } + // We do this to stop OAuth providers from creating an account // when signups are disabled if (env('NEXT_PUBLIC_DISABLE_SIGNUP') === 'true') { diff --git a/packages/tsconfig/process-env.d.ts b/packages/tsconfig/process-env.d.ts index 58447155b..5ef087199 100644 --- a/packages/tsconfig/process-env.d.ts +++ b/packages/tsconfig/process-env.d.ts @@ -9,6 +9,8 @@ declare namespace NodeJS { NEXT_PRIVATE_OIDC_WELL_KNOWN?: string; NEXT_PRIVATE_OIDC_CLIENT_ID?: string; NEXT_PRIVATE_OIDC_CLIENT_SECRET?: string; + NEXT_PRIVATE_OIDC_ALLOW_SIGNUP?: string; + NEXT_PRIVATE_OIDC_SKIP_VERIFY?: string; NEXT_PRIVATE_DATABASE_URL: string; NEXT_PRIVATE_ENCRYPTION_KEY: string; diff --git a/turbo.json b/turbo.json index c2057dcf3..a28e2e3a5 100644 --- a/turbo.json +++ b/turbo.json @@ -2,20 +2,12 @@ "$schema": "https://turbo.build/schema.json", "pipeline": { "build": { - "dependsOn": [ - "prebuild", - "^build" - ], - "outputs": [ - ".next/**", - "!.next/cache/**" - ] + "dependsOn": ["prebuild", "^build"], + "outputs": [".next/**", "!.next/cache/**"] }, "prebuild": { "cache": false, - "dependsOn": [ - "^prebuild" - ] + "dependsOn": ["^prebuild"] }, "lint": { "cache": false @@ -31,9 +23,7 @@ "persistent": true }, "start": { - "dependsOn": [ - "^build" - ], + "dependsOn": ["^build"], "cache": false, "persistent": true }, @@ -41,18 +31,14 @@ "cache": false }, "test:e2e": { - "dependsOn": [ - "^build" - ], + "dependsOn": ["^build"], "cache": false }, "translate:compile": { "cache": false } }, - "globalDependencies": [ - "**/.env.*local" - ], + "globalDependencies": ["**/.env.*local"], "globalEnv": [ "APP_VERSION", "NEXT_PRIVATE_ENCRYPTION_KEY", @@ -83,6 +69,8 @@ "NEXT_PRIVATE_OIDC_WELL_KNOWN", "NEXT_PRIVATE_OIDC_CLIENT_ID", "NEXT_PRIVATE_OIDC_CLIENT_SECRET", + "NEXT_PRIVATE_OIDC_ALLOW_SIGNUP", + "NEXT_PRIVATE_OIDC_SKIP_VERIFY", "NEXT_PUBLIC_UPLOAD_TRANSPORT", "NEXT_PRIVATE_UPLOAD_ENDPOINT", "NEXT_PRIVATE_UPLOAD_FORCE_PATH_STYLE",