{"record":{"id":"acd668f72451e908","repo":"bytedance/deer-flow","slug":"your-email-could-not-be-verified-by-the-identity-p","errorCode":null,"errorMessage":"Your email could not be verified by the identity provider. Please contact your administrator.","messagePattern":"Your email could not be verified by the identity provider\\. Please contact your administrator\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"backend/app/gateway/auth/user_provisioning.py","lineNumber":45,"sourceCode":") -> dict:\n    \"\"\"Resolve an OIDC identity to a DeerFlow user.\n\n    Flow:\n    1. Look up existing user by (provider, subject)\n    2. If not found, enforce domain/email-verified rules\n    3. Block if a local account already owns the email (never auto-link)\n    4. Auto-create if enabled\n\n    Returns a dict with ``user`` (the User model instance) and ``created`` (bool).\n    \"\"\"\n    # 1. Existing OAuth link\n    existing = await local_provider.get_user_by_oauth(provider_id, identity.subject)\n    if existing:\n        return {\"user\": existing, \"created\": False}\n\n    # 2. Verified email requirement\n    if provider_config.require_verified_email and not identity.email_verified:\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=(\"Your email could not be verified by the identity provider. Please contact your administrator.\"),\n        )\n\n    if not identity.email:\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=\"The identity provider did not provide an email address.\",\n        )\n\n    email = identity.email.lower()\n\n    # 3. Domain restriction\n    if provider_config.allowed_email_domains:\n        domain = email.rsplit(\"@\", 1)[-1]\n        if domain not in {d.lower().lstrip(\"@\") for d in provider_config.allowed_email_domains}:\n            raise HTTPException(\n                status_code=status.HTTP_403_FORBIDDEN,","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/auth/user_provisioning.py#L27-L63","documentation":"HTTP 403 raised during SSO/OIDC user provisioning when the provider is configured with require_verified_email=true but the identity returned by the IdP has email_verified false or missing. DeerFlow refuses to provision or log in a user whose email the identity provider has not verified, because an unverified email cannot be trusted as an account identifier. Note the early return for an existing OAuth link means this only bites on first login or after the link table is cleared.","triggerScenarios":"First-time OIDC login where config.yaml's provider entry sets require_verified_email: true and the ID token / userinfo carries email_verified=false (or omits the claim). Any subsequent call to the provisioning function with no existing oauth link row for (provider_id, identity.subject).","commonSituations":"Keycloak/Dex/Auth0 test realms where users are created without email verification; enterprise IdPs that never emit email_verified; enabling require_verified_email after users were already using SSO; claim-name customization that drops the verified flag.","solutions":["Verify the user's email at the identity provider, then retry the SSO login","Fix the provider's claim mapping so email_verified is emitted in the ID token or userinfo","If the provider genuinely cannot assert verification, set require_verified_email: false for that provider in config.yaml and restart the Gateway"],"exampleFix":"# config.yaml (provider entry)\n# before\nrequire_verified_email: true\n# after\nrequire_verified_email: false","handlingStrategy":"validation","validationCode":"# In an OIDC callback wrapper, check the claim before calling provisioning\nidentity = await provider.exchange_code(code)\nif provider_config.require_verified_email and not identity.email_verified:\n    return RedirectResponse(\"/login?error=email_not_verified\")","typeGuard":null,"tryCatchPattern":"from fastapi import HTTPException\ntry:\n    result = await provision_oauth_user(provider_id, identity, provider_config)\nexcept HTTPException as e:\n    if e.status_code == 403 and \"verified\" in e.detail:\n        return redirect_to_login(\"email_not_verified\")  # actionable user message\n    raise","preventionTips":["Keep require_verified_email: true in production and only relax it for dev IdPs","Verify the IdP emits email_verified in a staging login before rolling out","Surface the 403 detail verbatim in the login UI so users know to contact the admin"],"tags":["auth","oidc","sso","http-403","user-provisioning"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}