[GH-ISSUE #1160] OIDC redirect issue #17254

Closed
opened 2026-04-15 15:19:07 -05:00 by GiteaMirror · 14 comments
Owner

Originally created by @abhishek-butola on GitHub (Jan 9, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/1160

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create OIDC service (central-auth-app);
export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "pg",
    schema: schema,
  }),
  emailAndPassword: {
    enabled: true,
  },
  secret: process.env.BETTER_AUTH_SECRET,
  baseUrl: process.env.BETTER_AUTH_URL,
  plugins: [
    oidcProvider({
      loginPage: "/login",
      allowDynamicClientRegistration: true,
      requirePKCE: true,
      consentPage: "/oauth/consent",
    }),

    openAPI(),
  ],
});
//react client
export const authClient = createAuthClient({
  baseURL: "https://central-auth-app.com",
  plugins: [oidcClient()],
});
  1. Register a client "client-app" oauth/register.

  2. Create a "client-app" which uses "central-auth-app.com" in generic oauth plugin.

export const auth = betterAuth({

  database: drizzleAdapter(db, {
    provider: 'pg',
    schema: schema,
  }),
  emailAndPassword: {
    enabled: true,

  },

  account: {

    accountLinking: {
      enabled: true,
      trustedProviders: ['test'],
    },
  },

  secret: process.env.BETTER_AUTH_SECRET,
  baseUrl: 'http://client-app.com',
  plugins: [
    genericOAuth({
      config: [
        {
          providerId: 'test',
          clientId: 'nvkafqizujtfacldfdvrettvdkvpiajr',
          clientSecret: 'ixndgtbzrnnkncylkfvmorytwibfselp',
          authorizationUrl: 'https://central-auth-app.com/api/auth/oauth2/authorize',
          tokenUrl: 'https://central-auth-app.com/api/auth/oauth2/token',
          scopes: ['openid', 'profile', 'email'],
          pkce: true,
        },
      ],
    }),

  ],
})
  1. In client app, button onClick event
const data = await authClient.signIn.oauth2(
           {
             providerId: 'test',
             callbackURL: '/reports/property',
           },
           {
             throw: false,
           },
         )

This will redirect to the https://central-auth-app.com/login?client_id=things...other query params.

  1. In central auth app, when login button is clicked this event should redirect to consent or client screen correctly.
 const res = await authClient.signIn.email({
        email: data.email,
        password: data.password,
      });

Current vs. Expected behavior

I get the 302. but redirect doesn't happen. It fetches the consent document instead. and stay stucked.

image

I am able to fix this redirect using fetchOptions.

  const res = await authClient.signIn.email({
        email: data.email,
        password: data.password,
        fetchOptions: {
          onSuccess(context) {
            if (context.response.redirected) {
              window.location.href = context.response.url;
            }
          },
        },
      });

It goes to consent screen after this. and everything works fine.

Tried, redirect:"follow", it didn't work.

Now, consent is accepted. I sign out and try to sign in again. It doesn't have to go through consent screen again.
Instead it can just redirect.

But, i get cors error. Instead of redirecting, it tries to fetch the redirect url. And the fetchoptions like above doesn't work here.

image

Is this how it supposed to be or i am missing some step here?

What version of Better Auth are you using?

1.1.10

Provide environment information

OS: macos
Browser: chrome, safari and firefox.

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)

No response

Additional context

Tried on localhost and vercel subdomain.

Originally created by @abhishek-butola on GitHub (Jan 9, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/1160 ### Is this suited for github? - [X] Yes, this is suited for github ### To Reproduce 1. Create OIDC service (central-auth-app); ``` export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, }), emailAndPassword: { enabled: true, }, secret: process.env.BETTER_AUTH_SECRET, baseUrl: process.env.BETTER_AUTH_URL, plugins: [ oidcProvider({ loginPage: "/login", allowDynamicClientRegistration: true, requirePKCE: true, consentPage: "/oauth/consent", }), openAPI(), ], }); ``` ``` //react client export const authClient = createAuthClient({ baseURL: "https://central-auth-app.com", plugins: [oidcClient()], }); ``` 2. Register a client "client-app" oauth/register. 3. Create a "client-app" which uses "central-auth-app.com" in generic oauth plugin. ``` export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg', schema: schema, }), emailAndPassword: { enabled: true, }, account: { accountLinking: { enabled: true, trustedProviders: ['test'], }, }, secret: process.env.BETTER_AUTH_SECRET, baseUrl: 'http://client-app.com', plugins: [ genericOAuth({ config: [ { providerId: 'test', clientId: 'nvkafqizujtfacldfdvrettvdkvpiajr', clientSecret: 'ixndgtbzrnnkncylkfvmorytwibfselp', authorizationUrl: 'https://central-auth-app.com/api/auth/oauth2/authorize', tokenUrl: 'https://central-auth-app.com/api/auth/oauth2/token', scopes: ['openid', 'profile', 'email'], pkce: true, }, ], }), ], }) ``` 4. In client app, button onClick event ``` const data = await authClient.signIn.oauth2( { providerId: 'test', callbackURL: '/reports/property', }, { throw: false, }, ) ``` This will redirect to the https://central-auth-app.com/login?client_id=things...other query params. 5. In central auth app, when login button is clicked this event should redirect to consent or client screen correctly. ``` const res = await authClient.signIn.email({ email: data.email, password: data.password, }); ``` ### Current vs. Expected behavior I get the 302. but redirect doesn't happen. It fetches the consent document instead. and stay stucked. ![image](https://github.com/user-attachments/assets/7b66b9b3-377b-41d6-b017-72d85f16c872) I am able to fix this redirect using fetchOptions. ``` const res = await authClient.signIn.email({ email: data.email, password: data.password, fetchOptions: { onSuccess(context) { if (context.response.redirected) { window.location.href = context.response.url; } }, }, }); ``` It goes to consent screen after this. and everything works fine. > Tried, redirect:"follow", it didn't work. Now, consent is accepted. I sign out and try to sign in again. It doesn't have to go through consent screen again. Instead it can just redirect. But, i get cors error. Instead of redirecting, it tries to fetch the redirect url. And the fetchoptions like above doesn't work here. ![image](https://github.com/user-attachments/assets/7942424f-8405-4aa8-997c-3c66bc5765ec) Is this how it supposed to be or i am missing some step here? ### What version of Better Auth are you using? 1.1.10 ### Provide environment information ```bash OS: macos Browser: chrome, safari and firefox. ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) _No response_ ### Additional context Tried on localhost and vercel subdomain.
GiteaMirror added the lockedbug labels 2026-04-15 15:19:07 -05:00
Author
Owner

@realtydev commented on GitHub (Jan 10, 2025):

also was wondering about this

<!-- gh-comment-id:2583128747 --> @realtydev commented on GitHub (Jan 10, 2025): also was wondering about this
Author
Owner

@Esmaay commented on GitHub (Feb 28, 2025):

is there any update on this? only seems to happen after a sign-in?

<!-- gh-comment-id:2690497450 --> @Esmaay commented on GitHub (Feb 28, 2025): is there any update on this? only seems to happen after a sign-in?
Author
Owner

@Qodestackr commented on GitHub (Mar 19, 2025):

Trying to setup one too, its unstable

<!-- gh-comment-id:2736032467 --> @Qodestackr commented on GitHub (Mar 19, 2025): Trying to setup one too, its unstable
Author
Owner

@coopbri commented on GitHub (Apr 4, 2025):

EDIT: I solved the below, just had some CORS config issues on my client. The window.location.href = context.response.url; workaround works for me for now.

Ran into similar. I discovered setting

fetchOptions: {
  // ...
  mode: "no-cors",
}

causes the CORS error to go away and 302 still properly constructed, but the redirect doesn't occur.

I also noticed something strange, also in fetchOptions there are some other callbacks, including onError. onSuccess is not triggered for me, but onError is, and the error message/code is empty:

<!-- gh-comment-id:2779873859 --> @coopbri commented on GitHub (Apr 4, 2025): **EDIT:** I solved the below, just had some CORS config issues on my client. The `window.location.href = context.response.url;` workaround works for me for now. ~~Ran into similar. I discovered setting~~ ```ts fetchOptions: { // ... mode: "no-cors", } ``` ~~causes the CORS error to go away and 302 still properly constructed, but the redirect doesn't occur.~~ ~~I also noticed something strange, also in `fetchOptions` there are some other callbacks, including `onError`. `onSuccess` is not triggered for me, but `onError` is, and the error message/code is empty:~~ <img src="https://github.com/user-attachments/assets/737d2e40-bb73-411e-8936-6fc43f8fa804" width="400" />
Author
Owner

@Esmaay commented on GitHub (Apr 5, 2025):

Ran into similar. I discovered setting

fetchOptions: {
// ...
mode: "no-cors",
}
causes the CORS error to go away and 302 still properly constructed, but the redirect doesn't occur.

I also noticed something strange, also in fetchOptions there are some other callbacks, including onError. onSuccess is not triggered for me, but onError is, and the error message/code is empty:

Hm yes, no-cors would not work since it makes the response unreadable and BetterAuth needs the response.

<!-- gh-comment-id:2780652830 --> @Esmaay commented on GitHub (Apr 5, 2025): > Ran into similar. I discovered setting > > fetchOptions: { > // ... > mode: "no-cors", > } > causes the CORS error to go away and 302 still properly constructed, but the redirect doesn't occur. > > I also noticed something strange, also in `fetchOptions` there are some other callbacks, including `onError`. `onSuccess` is not triggered for me, but `onError` is, and the error message/code is empty: > > <img alt="" width="400" src="https://private-user-images.githubusercontent.com/20056195/430562044-737d2e40-bb73-411e-8936-6fc43f8fa804.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDM4NDk3OTMsIm5iZiI6MTc0Mzg0OTQ5MywicGF0aCI6Ii8yMDA1NjE5NS80MzA1NjIwNDQtNzM3ZDJlNDAtYmI3My00MTFlLTg5MzYtNmZjNDNmOGZhODA0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA0MDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNDA1VDEwMzgxM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTE5MWQ4NzcxNGRmMjQ1NzdjODdkYmM0YmFkNzYwYTU3YzRhNjZiNDM1ZmFlNTI3MTc3YzQ4MmU3OWZjZjUwMTYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.5HVnw9Yrl2oo-v2FblFflO81zTQvBht6YswRd-Zt2rU"> Hm yes, no-cors would not work since it makes the response unreadable and BetterAuth needs the response.
Author
Owner

@IhsenBouallegue commented on GitHub (May 12, 2025):

Same problem. This basically renders the OIDC plugin unusable, right? Sadly all of my app is based on it and I don't want to drop better auth :/

<!-- gh-comment-id:2871840731 --> @IhsenBouallegue commented on GitHub (May 12, 2025): Same problem. This basically renders the OIDC plugin unusable, right? Sadly all of my app is based on it and I don't want to drop better auth :/
Author
Owner

@Esmaay commented on GitHub (May 12, 2025):

Yes well, for me the flow works fine if already logged in, but if they need to login it fails for me. I dont think there are many alternatives which offer OIDC provider support

<!-- gh-comment-id:2872051982 --> @Esmaay commented on GitHub (May 12, 2025): Yes well, for me the flow works fine if already logged in, but if they need to login it fails for me. I dont think there are many alternatives which offer OIDC provider support
Author
Owner

@IhsenBouallegue commented on GitHub (May 13, 2025):

@Esmaay works for me too when user is not logged in and when the consent was not given already (with the above hack). So this is clearly a bug. But I can't find where in the code this happens. Any pointers would be nice. Because we can just compare the flow that works already and the one that does not and adjust accordingly.

<!-- gh-comment-id:2875692212 --> @IhsenBouallegue commented on GitHub (May 13, 2025): @Esmaay works for me too when user is not logged in and when the consent was not given already (with the above hack). So this is clearly a bug. But I can't find where in the code this happens. Any pointers would be nice. Because we can just compare the flow that works already and the one that does not and adjust accordingly.
Author
Owner

@IhsenBouallegue commented on GitHub (May 13, 2025):

@Bekacru I see that you implemented this awesome plugin. Can you please give us some pointers, when you find the time?

<!-- gh-comment-id:2875737831 --> @IhsenBouallegue commented on GitHub (May 13, 2025): @Bekacru I see that you implemented this awesome plugin. Can you please give us some pointers, when you find the time?
Author
Owner

@IhsenBouallegue commented on GitHub (May 13, 2025):

I seem to have found the problem and fixed it, if someone tests it let me know. Everything is explained in the PR #2641

<!-- gh-comment-id:2876904824 --> @IhsenBouallegue commented on GitHub (May 13, 2025): I seem to have found the problem and fixed it, if someone tests it let me know. Everything is explained in the PR #2641
Author
Owner

@BadPirate commented on GitHub (May 30, 2025):

While all the comments in this thread are related to OIDC post-auth flow, I think there are two issues going on here:

  • When using the OIDC provider plugin with email signin and consent is required, authClient.signIn.email() returns HTML content of the consent page instead of properly handling the redirect. This breaks the authentication flow for applications using fetch-based signin. -- The original issue @abhishek-butola documented, and provided a work around for
  • Some more general issues in the post auth flow regarding CORS setup for specific frameworks. That @IhsenBouallegue has provided a PR for #2641 @IhsenBouallegue

I'm working on a fix for the first issue. as currently it makes oidcProvider unusable as documented for any flows that require prompting (as well there is another task pointing out that someone hardcoded prompt == true in a part of the auth flow) -- Hopefully have a PR up today.

<!-- gh-comment-id:2923637205 --> @BadPirate commented on GitHub (May 30, 2025): While all the comments in this thread are related to OIDC post-auth flow, I think there are two issues going on here: * When using the OIDC provider plugin with email signin and consent is required, `authClient.signIn.email()` returns HTML content of the consent page instead of properly handling the redirect. This breaks the authentication flow for applications using fetch-based signin. -- The original issue @abhishek-butola documented, and provided a work around for * Some more general issues in the post auth flow regarding CORS setup for specific frameworks. That @IhsenBouallegue has provided a PR for #2641 @IhsenBouallegue I'm working on a fix for the first issue. as currently it makes oidcProvider unusable as documented for any flows that require prompting (as well there is another task pointing out that someone hardcoded prompt == true in a part of the auth flow) -- Hopefully have a PR up today.
Author
Owner

@BadPirate commented on GitHub (Jun 2, 2025):

Resolved by #2849 - Fixes both the redirect issue, as well as the CORS issue (which was happening because fetch was trying to redirect cross domain, which it can't do.

<!-- gh-comment-id:2931663232 --> @BadPirate commented on GitHub (Jun 2, 2025): Resolved by #2849 - Fixes both the redirect issue, as well as the CORS issue (which was happening because fetch was trying to redirect cross domain, which it can't do.
Author
Owner

@zackify commented on GitHub (Jun 2, 2025):

We need a release. It's been a while and a lot of fixes are on main

<!-- gh-comment-id:2932655131 --> @zackify commented on GitHub (Jun 2, 2025): We need a release. It's been a while and a lot of fixes are on main
Author
Owner

@cameronbensimon commented on GitHub (Aug 5, 2025):

I'm experiencing the same issue...

<!-- gh-comment-id:3154740695 --> @cameronbensimon commented on GitHub (Aug 5, 2025): I'm experiencing the same issue...
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#17254