{"record":{"id":"2242882adb5de83e","repo":"immich-app/immich","slug":"oauth-profile-does-not-have-an-email-address","errorCode":null,"errorMessage":"OAuth profile does not have an email address","messagePattern":"OAuth profile does not have an email address","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/auth.service.ts","lineNumber":341,"sourceCode":"\n    const role = this.getRoleClaim(profile, roleClaim);\n    const isAdmin = role === 'admin';\n\n    if (user && role && isAdmin !== user.isAdmin) {\n      user = await this.userRepository.update(user.id, { isAdmin });\n    }\n\n    // register new user\n    if (!user) {\n      if (!autoRegister) {\n        this.logger.warn(\n          `Unable to register ${profile.sub}/${normalizedEmail || '(no email)'}. User does not exist and auto registering is disabled. To enable set OAuth Auto Register to true in admin settings.`,\n        );\n        throw new BadRequestException('OAuth authentication failed');\n      }\n\n      if (!normalizedEmail) {\n        throw new BadRequestException('OAuth profile does not have an email address');\n      }\n\n      this.logger.log(`Registering new user: ${profile.sub}/${normalizedEmail}`);\n\n      const storageLabel = this.getClaim(profile, {\n        key: storageLabelClaim,\n        default: '',\n        isValid: (value: unknown): value is string => typeof value === 'string',\n      });\n      const storageQuota = this.getClaim(profile, {\n        key: storageQuotaClaim,\n        default: defaultStorageQuota,\n        isValid: (value: unknown) => Number(value) >= 0,\n      });\n\n      user = await this.createUser({\n        name:\n          profile.name ||","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/auth.service.ts#L323-L359","documentation":"BadRequestException (HTTP 400) thrown when autoRegister is enabled but the IdP profile has no usable email (profile.email missing/empty after trim+lowercase). Immich requires an email to create a user, so it refuses to provision. Only reached in the registration branch, after the autoRegister check.","triggerScenarios":"POST /oauth/callback for a new identity, autoRegister=true, but the IdP token/userinfo response omitted the email claim or sent an empty string. Common with IdP configs that gate email behind extra scopes.","commonSituations":"IdP does not advertise the email scope (e.g. OIDC 'email' scope missing); user declined email sharing on consent; custom OIDC provider with non-standard claim names; misconfigured storageLabelClaim/emailClaim mapping.","solutions":["Request the 'email' scope (and 'profile' if needed) in the OAuth client config on the IdP.","Ensure the IdP actually issues the email claim in userinfo/id_token.","If using a custom claim name, confirm Immich is configured to read email from the standard claim.","Have the user re-consent so the email is released."],"exampleFix":"// before\n// IdP client scopes: ['openid']\nPOST /oauth/callback { url }\n// -> 400 OAuth profile does not have an email address\n\n// after\n// IdP client scopes: ['openid', 'email', 'profile']\nPOST /oauth/callback { url }","handlingStrategy":"validation","validationCode":"function profileHasEmail(profile: { email?: string }): boolean {\n  return Boolean(profile.email && profile.email.trim().length);\n}","typeGuard":"function hasEmailClaim(profile: { email?: unknown }): profile is { email: string } {\n  return typeof profile.email === 'string' && profile.email.trim().length > 0;\n}","tryCatchPattern":"try {\n  await axios.post('/oauth/callback', { url });\n} catch (e) {\n  if (e.response?.data?.message === 'OAuth profile does not have an email address') {\n    showHelp('Re-consent on the IdP, or ask admin to request the email scope.');\n  } else throw e;\n}","preventionTips":["Request the OIDC 'email' scope in the IdP client.","Verify the IdP returns the email claim in userinfo/id_token.","For custom claim names, configure Immich to read the right field."],"tags":["auth","oauth","provisioning","nestjs","immich"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}