#17600·langfuse

Azure AD B2C sign-in fails: Account model missing not_before and id_token_expires_in

Author: ZaidAfane3Created Sep 17, 2026Updated Sep 17, 2026
Labelsbugfeat-authself-hosting

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_ERROR

Notably 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

  1. 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/custom as a redirect URI.
  2. 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>
  3. Click the provider button on the sign-in page and complete authentication.
  4. 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

prisma
  not_before               Int?    // Azure AD B2C
  id_token_expires_in      Int?    // Azure AD B2C

and a migration mirroring 20231223230008_accounts_add_cols_azure_ad_auth:

sql
-- 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_before returns no results, so the issue looks present on current main.
  • 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.