Azure AD B2C sign-in fails: Account model missing not_before and id_token_expires_in
Describe the bug
Signing in with Azure AD B2C as a custom OAuth provider (AUTH_CUSTOM_*) fails at account creation, after authentication has already succeeded. The browser lands back on /auth/sign-in?error=Callback.
B2C returns two fields in its token response that the Account model does not have — not_before and id_token_expires_in — so prisma.account.create() rejects the call:
error prisma:error
Invalid `prisma.account.create()` invocation:
{
data: {
provider: "custom",
type: "oauth",
providerAccountId: "<redacted>",
id_token: "<redacted>",
token_type: "Bearer",
not_before: <redacted>,
~~~~~~~~~~
id_token_expires_in: 3600,
...
}
}
error [NEXT_AUTH] adapter_error_linkAccount
error [NEXT_AUTH] OAUTH_CALLBACK_HANDLER_ERRORNotably the OAuth flow itself is fine — B2C authenticates the user, the ID token carries a valid email claim, and Auth.js accepts the issuer. Only the persistence step fails, so no account is ever created and sign-in can never succeed.
This appears to be the same shape as #2468 (GitLab, unknown created_at).
To reproduce
- Register an application in an Azure AD B2C tenant with a sign-up/sign-in user flow, and add
https://<langfuse-host>/api/auth/callback/customas a redirect URI. - Configure the custom provider:
AUTH_CUSTOM_CLIENT_ID=<client id> AUTH_CUSTOM_CLIENT_SECRET=<client secret> AUTH_CUSTOM_ISSUER=https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0 AUTH_CUSTOM_NAME=<display name> - Click the provider button on the sign-in page and complete authentication.
- Sign-in fails with
error=Callback; the container log shows the Prisma error above.
Expected behaviour
The account is created and the user is signed in, as with the other supported providers.
Suggested fix
Two nullable columns on Account, following the existing precedent for provider-specific fields:
packages/shared/prisma/schema.prisma
not_before Int? // Azure AD B2C
id_token_expires_in Int? // Azure AD B2Cand a migration mirroring 20231223230008_accounts_add_cols_azure_ad_auth:
-- AlterTable
ALTER TABLE "Account" ADD COLUMN "not_before" INTEGER,
ADD COLUMN "id_token_expires_in" INTEGER;The model already carries expires_in / ext_expires_in (20231223230008_accounts_add_cols_azure_ad_auth), refresh_token_expires_in (20240913185822_...) and created_at // GitLab (20241009042557_...), so widening it for a provider's extra token fields looks like the established approach. Both columns are nullable, so the migration is additive and no existing row or provider is affected.
If you would rather filter unknown fields in the adapter than widen the schema, that would fix this class of problem for every provider at once — happy to go either way, which is why I am asking before opening a PR. I can put up the PR for whichever you prefer.
Additional context
- Langfuse v3.224.1, self-hosted. Checked v3.225.8 and v4.37.0 — neither contains these columns, and a repository search for
not_beforereturns no results, so the issue looks present on currentmain. - Azure AD B2C is not listed as a supported provider in the SSO docs, so
AUTH_CUSTOM_*is the documented route for it. Worth noting the generic custom provider otherwise works with B2C — this is the only thing blocking it.
Source: langfuse/langfuse