[GH-ISSUE #6544] Getting please_restart_the_process with genericOAuth2 constantly, code not consumed #10549

Closed
opened 2026-04-13 06:46:06 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @gfrn on GitHub (Dec 5, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6544

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Login, the first one will succeed
  2. Trigger a login either from the frontend with signIn or from the backend with api.signIn
  3. The second login will fail as long as there is a session_token in your cookies. You may have to log in a few times for this to occur
  4. You will be redirected to the error page with code please_restart_the_process
  5. If you delete your cookies (session_token alone seems to do the trick), logins now work

Current vs. Expected behavior

I expected my cookies to be deleted and regenerated with a fresh session, but instead, the old cookies remain, and worse still, I get an error page whenever I try to log in.

I've tried deleting them with a hook (deleteSessionCookie in after on /sign-in or callback), but that doesn't happen either, presumably because of the 302 redirect. This is consistent regardless of the sign-in process being started through the frontend or backend.

Although I've enabled debugging, no useful information is printed at all.

The authorisation code isn't consumed, which means that something is happening before the code is even attempted to be exchanged. The backend/frontend are receiving cookie headers, and the browser seems to respect set-cookie headers whenever they're sent, although they're not always sent.

Is there any way I can get more useful information, or at least some indication as to why the process is failing? The current error message provides no useful information.

What version of Better Auth are you using?

1.4.5

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Sun Oct 19 18:47:49 UTC 2025",
    "release": "6.17.4-200.fc42.x86_64",
    "cpuCount": 8,
    "cpuModel": "11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz",
    "totalMemory": "31.08 GB",
    "freeMemory": "7.71 GB"
  },
  "node": {
    "version": "v24.5.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.5.1"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "15.5.7"
    },
    {
      "name": "react",
      "version": "19.1.1"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.4.5",
    "config": {
      "logger": {
        "disabled": false,
        "level": "debug"
      },
      "advanced": {
        "cookiePrefix": "scaup"
      },
      "plugins": [
        {
          "name": "generic-oauth",
          "config": {
            "id": "generic-oauth",
            "endpoints": {},
            "$ERROR_CODES": {
              "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration",
              "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.",
              "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider",
              "PROVIDER_ID_REQUIRED": "Provider ID is required",
              "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.",
              "SESSION_REQUIRED": "Session is required"
            }
          }
        },
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        }
      ]
    }
  }
}

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

Client, Backend

Auth config (if applicable)

export const auth = betterAuth({
  logger: {
    disabled: false,
    level: "debug",
    log: (level, message, ...args) => {
      // Custom logging implementation
      console.log(`Better auth [${level}] ${message}`, ...args);
    },
  },
  advanced: {
    cookiePrefix: "scaup",
  },
  plugins: [
    genericOAuth({
      config: [
        {
          providerId: "diamond",
          clientId: process.env.OAUTH_CLIENT_ID!,
          clientSecret: process.env.OAUTH_CLIENT_SECRET,
          discoveryUrl: process.env.OAUTH_DISCOVERY_ENDPOINT,
          scopes: ["openid"],
        },
      ],
    }),
    nextCookies(),
  ],
});

Additional context

No response

Originally created by @gfrn on GitHub (Dec 5, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6544 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Login, the first one will succeed 2. Trigger a login either from the frontend with `signIn` or from the backend with `api.signIn` 3. The second login will fail as long as there is a `session_token` in your cookies. You may have to log in a few times for this to occur 4. You will be redirected to the error page with code `please_restart_the_process` 5. If you delete your cookies (session_token alone seems to do the trick), logins now work ### Current vs. Expected behavior I expected my cookies to be deleted and regenerated with a fresh session, but instead, the old cookies remain, and worse still, I get an error page whenever I try to log in. I've tried deleting them with a hook (`deleteSessionCookie` in `after` on `/sign-in` or callback), but that doesn't happen either, presumably because of the 302 redirect. This is consistent regardless of the sign-in process being started through the frontend or backend. Although I've enabled debugging, no useful information is printed at all. The authorisation code isn't consumed, which means that something is happening before the code is even attempted to be exchanged. The backend/frontend are receiving `cookie` headers, and the browser seems to respect `set-cookie` headers whenever they're sent, although they're not always sent. Is there any way I can get more useful information, or at least some indication as to why the process is failing? The current error message provides no useful information. ### What version of Better Auth are you using? 1.4.5 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Sun Oct 19 18:47:49 UTC 2025", "release": "6.17.4-200.fc42.x86_64", "cpuCount": 8, "cpuModel": "11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz", "totalMemory": "31.08 GB", "freeMemory": "7.71 GB" }, "node": { "version": "v24.5.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.5.1" }, "frameworks": [ { "name": "next", "version": "15.5.7" }, { "name": "react", "version": "19.1.1" } ], "databases": null, "betterAuth": { "version": "^1.4.5", "config": { "logger": { "disabled": false, "level": "debug" }, "advanced": { "cookiePrefix": "scaup" }, "plugins": [ { "name": "generic-oauth", "config": { "id": "generic-oauth", "endpoints": {}, "$ERROR_CODES": { "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration", "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.", "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider", "PROVIDER_ID_REQUIRED": "Provider ID is required", "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.", "SESSION_REQUIRED": "Session is required" } } }, { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ logger: { disabled: false, level: "debug", log: (level, message, ...args) => { // Custom logging implementation console.log(`Better auth [${level}] ${message}`, ...args); }, }, advanced: { cookiePrefix: "scaup", }, plugins: [ genericOAuth({ config: [ { providerId: "diamond", clientId: process.env.OAUTH_CLIENT_ID!, clientSecret: process.env.OAUTH_CLIENT_SECRET, discoveryUrl: process.env.OAUTH_DISCOVERY_ENDPOINT, scopes: ["openid"], }, ], }), nextCookies(), ], }); ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 06:46:06 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 5, 2025):

(tag @better-auth-agent if you would like an answer from the Agent)

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3616288891 --> @better-auth-agent[bot] commented on GitHub (Dec 5, 2025): (tag @better-auth-agent if you would like an answer from the Agent) _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 5, 2025):

Hi there, thanks for reaching out! Based on your description, it looks like the stale session token (the cookie) is interfering with the OAuth flow, so the authorization code isn’t being consumed and you’re getting the "please_restart_the_process" error. Here are some troubleshooting steps you might consider:

  1. Verify that your session cookie is being cleared completely before starting a new OAuth flow. Since the nextCookies plugin is involved, double-check your after hook to ensure the cookie deletion happens before the 302 redirect.

  2. Enable and review debug logs closely. With your debug logging enabled, check to see if any early termination or casing errors appear during the OAuth exchange. Sometimes, network intermediaries or browser behaviors can prevent the proper setting or deletion of cookies.

  3. Ensure that nothing in your application or middleware is persisting the session cookie unexpectedly, and confirm that the genericOAuth plugin is correctly consuming and invalidating the old authorization code after a successful login.

If you’ve tried these steps already, could you share any additional logs or details that might help narrow down which part of the flow is missing its cookie clearance? Tag @better-auth-agent if you would like an answer from the Agent.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3616292686 --> @better-auth-agent[bot] commented on GitHub (Dec 5, 2025): Hi there, thanks for reaching out! Based on your description, it looks like the stale session token (the cookie) is interfering with the OAuth flow, so the authorization code isn’t being consumed and you’re getting the "please_restart_the_process" error. Here are some troubleshooting steps you might consider: 1. Verify that your session cookie is being cleared completely before starting a new OAuth flow. Since the nextCookies plugin is involved, double-check your after hook to ensure the cookie deletion happens before the 302 redirect. 2. Enable and review debug logs closely. With your debug logging enabled, check to see if any early termination or casing errors appear during the OAuth exchange. Sometimes, network intermediaries or browser behaviors can prevent the proper setting or deletion of cookies. 3. Ensure that nothing in your application or middleware is persisting the session cookie unexpectedly, and confirm that the genericOAuth plugin is correctly consuming and invalidating the old authorization code after a successful login. If you’ve tried these steps already, could you share any additional logs or details that might help narrow down which part of the flow is missing its cookie clearance? Tag @better-auth-agent if you would like an answer from the Agent. <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@dosubot[bot] commented on GitHub (Dec 5, 2025):

Hi @gfrn! I'm Dosu and I’m helping the better-auth team.

The root cause of the please_restart_the_process error is a failure in OAuth state validation before the code exchange—usually because the encrypted state cookie (oauth_state) is missing, expired, or not readable during the callback. This matches your observation that the code is never consumed and deleting the session_token cookie allows login to work again. This is often triggered by browser-level cookie isolation (e.g., cookies set on one domain or subdomain are not available on another during the OAuth callback), or by double-callbacks from misconfigured URLs or frontend navigation issues [source] [source].

302 redirects can interfere with cookie deletion—if you try to delete cookies in a hook after a redirect is already in progress, the browser may not process the Set-Cookie header as expected. The next-cookies plugin relies on set-cookie headers being present in the response; if they're missing or not processed due to redirect timing, cookies won't be updated or deleted [source].

To diagnose and fix:

  • Make sure your cookie configuration explicitly sets the domain to your root domain (e.g., .example.com), SameSite=None, and Secure=true for all OAuth-related cookies. For localhost, use domain: "localhost" (no protocol) and set secure: false if not using HTTPS [source].
  • Ensure all relevant domains (localhost, preview, production) are included in trustedOrigins and registered as callback URLs with your OAuth provider.
  • Always initiate OAuth sign-in from the client using the Better Auth client SDK, and use a user-facing route as the callbackURL (not the API callback endpoint) to avoid double-callback and state errors [source].
  • Clear all cookies for your domain before testing, as stale cookies can cause repeated failures.
  • If you need to debug Set-Cookie headers, add middleware in your framework to log outgoing response headers, since Better Auth's built-in debug logging does not show cookie operations [source].

If these steps don't resolve the issue, be aware that a recent update to Better Auth (after v1.4.5) rewrote the OAuth Proxy logic to better handle state validation and cross-origin issues. Upgrading may resolve persistent please_restart_the_process errors related to state/cookie handling [source].

Let me know if you want a sample config for cookie settings or more targeted debugging steps.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3616307439 --> @dosubot[bot] commented on GitHub (Dec 5, 2025): <!-- Greeting --> Hi @gfrn! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The root cause of the please_restart_the_process error is a failure in OAuth state validation before the code exchange—usually because the encrypted state cookie (oauth_state) is missing, expired, or not readable during the callback. This matches your observation that the code is never consumed and deleting the session_token cookie allows login to work again. This is often triggered by browser-level cookie isolation (e.g., cookies set on one domain or subdomain are not available on another during the OAuth callback), or by double-callbacks from misconfigured URLs or frontend navigation issues [[source]](https://github.com/better-auth/better-auth/issues/5563) [[source]](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/oauth2/state.ts#L49-L207). 302 redirects can interfere with cookie deletion—if you try to delete cookies in a hook after a redirect is already in progress, the browser may not process the Set-Cookie header as expected. The next-cookies plugin relies on set-cookie headers being present in the response; if they're missing or not processed due to redirect timing, cookies won't be updated or deleted [[source]](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/integrations/next-js.ts#L24-L85). To diagnose and fix: - Make sure your cookie configuration explicitly sets the domain to your root domain (e.g., .example.com), SameSite=None, and Secure=true for all OAuth-related cookies. For localhost, use domain: "localhost" (no protocol) and set secure: false if not using HTTPS [[source]](https://github.com/better-auth/better-auth/issues/5658). - Ensure all relevant domains (localhost, preview, production) are included in trustedOrigins and registered as callback URLs with your OAuth provider. - Always initiate OAuth sign-in from the client using the Better Auth client SDK, and use a user-facing route as the callbackURL (not the API callback endpoint) to avoid double-callback and state errors [[source]](https://github.com/better-auth/better-auth/issues/5563). - Clear all cookies for your domain before testing, as stale cookies can cause repeated failures. - If you need to debug Set-Cookie headers, add middleware in your framework to log outgoing response headers, since Better Auth's built-in debug logging does not show cookie operations [[source]](https://github.com/better-auth/better-auth/issues/3169). If these steps don't resolve the issue, be aware that a recent update to Better Auth (after v1.4.5) rewrote the OAuth Proxy logic to better handle state validation and cross-origin issues. Upgrading may resolve persistent please_restart_the_process errors related to state/cookie handling [[source]](https://github.com/better-auth/better-auth/issues/5563). Let me know if you want a sample config for cookie settings or more targeted debugging steps. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c22184ee-c235-4665-8b10-e12efeef235f?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20root%20cause%20of%20the%20please_restart_the_process%20error%20is%20a%20failure%20in%20OAuth%20state%20validation%20before%20the%20code%20exchange%E2%80%94usually%20because%20the%20encrypted%20state%20cookie%20%28oauth_state%29%20is%20missing%2C%20expired%2C%20or%20not%20readable%20during%20the%20callback.%20This%20matches%20your%20observation%20that%20the%20code%20is%20never%20consumed%20and%20deleting%20the%20session_token%20cookie%20allows%20login%20to%20work%20again.%20This%20is%20often%20triggered%20by%20browser-level%20cookie%20isolation%20%28e.g.%2C%20cookies%20set%20on%20one%20domain%20or%20subdomain%20are%20not%20available%20on%20another%20during%20the%20OAuth%20callback%29%2C%20or%20by%20double-callbacks%20from%20misconfigured%20URLs%20or%20frontend%20navigation%20issues%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/5563%29%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/oauth2/state.ts%23L49-L207%29.%0A%0A302%20redirects%20can%20interfere%20with%20cookie%20deletion%E2%80%94if%20you%20try%20to%20delete%20cookies%20in%20a%20hook%20after%20a%20redirect%20is%20already%20in%20progress%2C%20the%20browser%20may%20not%20process%20the%20Set-Cookie%20header%20as%20expected.%20The%20next-cookies%20plugin%20relies%20on%20set-cookie%20headers%20being%20present%20in%20the%20response%3B%20if%20they%27re%20missing%20or%20not%20processed%20due%20to%20redirect%20timing%2C%20cookies%20won%27t%20be%20updated%20or%20deleted%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/integrations/next-js.ts%23L24-L85%29.%0A%0ATo%20diagnose%20and%20fix%3A%0A%0A-%20Make%20sure%20your%20cookie%20configuration%20explicitly%20sets%20the%20domain%20to%20your%20root%20domain%20%28e.g.%2C%20.example.com%29%2C%20SameSite%3DNone%2C%20and%20Secure%3Dtrue%20for%20all%20OAuth-related%20cookies.%20For%20localhost%2C%20use%20domain%3A%20%22localhost%22%20%28no%20protocol%29%20and%20set%20secure%3A%20false%20if%20not%20using%20HTTPS%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/5658%29.%0A-%20Ensure%20all%20relevant%20domains%20%28localhost%2C%20preview%2C%20production%29%20are%20included%20in%20trustedOrigins%20and%20registered%20as%20callback%20URLs%20with%20your%20OAuth%20provider.%0A-%20Always%20initiate%20OAuth%20sign-in%20from%20the%20client%20using%20the%20Better%20Auth%20client%20SDK%2C%20and%20use%20a%20user-facing%20route%20as%20the%20callbackURL%20%28not%20the%20API%20callback%20endpoint%29%20to%20avoid%20double-callback%20and%20state%20errors%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/5563%29.%0A-%20Clear%20all%20cookies%20for%20your%20domain%20before%20testing%2C%20as%20stale%20cookies%20can%20cause%20repeated%20failures.%0A-%20If%20you%20need%20to%20debug%20Set-Cookie%20headers%2C%20add%20middleware%20in%20your%20framework%20to%20log%20outgoing%20response%20headers%2C%20since%20Better%20Auth%27s%20built-in%20debug%20logging%20does%20not%20show%20cookie%20operations%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/3169%29.%0A%0AIf%20these%20steps%20don%27t%20resolve%20the%20issue%2C%20be%20aware%20that%20a%20recent%20update%20to%20Better%20Auth%20%28after%20v1.4.5%29%20rewrote%20the%20OAuth%20Proxy%20logic%20to%20better%20handle%20state%20validation%20and%20cross-origin%20issues.%20Upgrading%20may%20resolve%20persistent%20please_restart_the_process%20errors%20related%20to%20state/cookie%20handling%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/5563%29.%0A%0ALet%20me%20know%20if%20you%20want%20a%20sample%20config%20for%20cookie%20settings%20or%20more%20targeted%20debugging%20steps.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6544)
Author
Owner

@gfrn commented on GitHub (Dec 5, 2025):

@dosubot This partly works, but there are no set-cookie headers on 302 responses, which don't set the state and result in the process failing either because of a stale state cookie, or an unspecified reason (please_restart_the_process)

I have some logic to redirect on 401s, which looks like this

const requestHeaders = await headers();
  const session = await auth.api.getSession({
    headers: requestHeaders,
  });

  const res = await authenticatedFetch(
    process.env.SERVER_API_URL! + url,
    {...init, credentials: "include"},
    session?.user.accessToken,
    false
  );

  if (res.status === 401) {
    const { url: redirectUrl } = await auth.api.signInSocial({
      body: {
        provider: "diamond",
        callbackURL: requestHeaders.get("x-path") ?? "/"
      },
    });
    redirect(redirectUrl!, );
  }

  return res;
<!-- gh-comment-id:3616740125 --> @gfrn commented on GitHub (Dec 5, 2025): @dosubot This partly works, but there are no set-cookie headers on 302 responses, which don't set the state and result in the process failing either because of a stale state cookie, or an unspecified reason (please_restart_the_process) I have some logic to redirect on 401s, which looks like this ``` const requestHeaders = await headers(); const session = await auth.api.getSession({ headers: requestHeaders, }); const res = await authenticatedFetch( process.env.SERVER_API_URL! + url, {...init, credentials: "include"}, session?.user.accessToken, false ); if (res.status === 401) { const { url: redirectUrl } = await auth.api.signInSocial({ body: { provider: "diamond", callbackURL: requestHeaders.get("x-path") ?? "/" }, }); redirect(redirectUrl!, ); } return res; ```
Author
Owner

@dosubot[bot] commented on GitHub (Dec 5, 2025):

The reason you're seeing missing set-cookie headers on 302 responses—and getting stale state or please_restart_the_process errors—is that the OAuth state cookie is set in the response from the signInSocial API call, not in the subsequent redirect. If you call auth.api.signInSocial and immediately perform a server-side redirect (using redirect(redirectUrl)), the browser never receives the Set-Cookie header, so the state cookie is never set. This causes the OAuth callback to fail before the code exchange, since the state can't be validated reference.

To fix this, you need to ensure the response from signInSocial (with its Set-Cookie header) is sent to the browser and processed before any redirect happens. In Next.js, this means you should not perform an immediate server-side redirect after the API call. Instead, either:

  • Call signInSocial from the client (using the Better Auth client SDK), then redirect the user to the returned URL on the client side, or
  • If you must initiate from the backend, send the signInSocial response (with Set-Cookie) to the browser, then perform the redirect on the client after the response is received.

The nextCookies plugin will only set cookies if the Set-Cookie header is present in the response; it cannot set cookies if you skip straight to a redirect reference.

For Next.js, make sure nextCookies is the last plugin in your array, and avoid triggering sign-in flows from server components—use server actions or API routes instead reference.

In summary: let the browser process the Set-Cookie header from the signInSocial response before redirecting. If you perform a server-side redirect before the response is sent, the state cookie will not be set and the OAuth flow will break reference.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3616770176 --> @dosubot[bot] commented on GitHub (Dec 5, 2025): <!-- Answer --> The reason you're seeing missing set-cookie headers on 302 responses—and getting stale state or please_restart_the_process errors—is that the OAuth state cookie is set in the response from the signInSocial API call, not in the subsequent redirect. If you call auth.api.signInSocial and immediately perform a server-side redirect (using redirect(redirectUrl)), the browser never receives the Set-Cookie header, so the state cookie is never set. This causes the OAuth callback to fail before the code exchange, since the state can't be validated [reference](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/api/routes/sign-in.ts#L155-L328). To fix this, you need to ensure the response from signInSocial (with its Set-Cookie header) is sent to the browser and processed before any redirect happens. In Next.js, this means you should not perform an immediate server-side redirect after the API call. Instead, either: - Call signInSocial from the client (using the Better Auth client SDK), then redirect the user to the returned URL on the client side, or - If you must initiate from the backend, send the signInSocial response (with Set-Cookie) to the browser, then perform the redirect on the client after the response is received. The nextCookies plugin will only set cookies if the Set-Cookie header is present in the response; it cannot set cookies if you skip straight to a redirect [reference](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/integrations/next-js.ts#L24-L85). For Next.js, make sure nextCookies is the last plugin in your array, and avoid triggering sign-in flows from server components—use server actions or API routes instead [reference](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/integrations/next.mdx#L93-L375). In summary: let the browser process the Set-Cookie header from the signInSocial response before redirecting. If you perform a server-side redirect before the response is sent, the state cookie will not be set and the OAuth flow will break [reference](https://github.com/better-auth/better-auth/issues/5563). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/9821b9eb-873c-46b4-9f9b-3762d749f4dc?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20reason%20you%27re%20seeing%20missing%20set-cookie%20headers%20on%20302%20responses%E2%80%94and%20getting%20stale%20state%20or%20please_restart_the_process%20errors%E2%80%94is%20that%20the%20OAuth%20state%20cookie%20is%20set%20in%20the%20response%20from%20the%20signInSocial%20API%20call%2C%20not%20in%20the%20subsequent%20redirect.%20If%20you%20call%20auth.api.signInSocial%20and%20immediately%20perform%20a%20server-side%20redirect%20%28using%20redirect%28redirectUrl%29%29%2C%20the%20browser%20never%20receives%20the%20Set-Cookie%20header%2C%20so%20the%20state%20cookie%20is%20never%20set.%20This%20causes%20the%20OAuth%20callback%20to%20fail%20before%20the%20code%20exchange%2C%20since%20the%20state%20can%27t%20be%20validated%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/api/routes/sign-in.ts%23L155-L328%29.%0A%0ATo%20fix%20this%2C%20you%20need%20to%20ensure%20the%20response%20from%20signInSocial%20%28with%20its%20Set-Cookie%20header%29%20is%20sent%20to%20the%20browser%20and%20processed%20before%20any%20redirect%20happens.%20In%20Next.js%2C%20this%20means%20you%20should%20not%20perform%20an%20immediate%20server-side%20redirect%20after%20the%20API%20call.%20Instead%2C%20either%3A%0A%0A-%20Call%20signInSocial%20from%20the%20client%20%28using%20the%20Better%20Auth%20client%20SDK%29%2C%20then%20redirect%20the%20user%20to%20the%20returned%20URL%20on%20the%20client%20side%2C%20or%0A-%20If%20you%20must%20initiate%20from%20the%20backend%2C%20send%20the%20signInSocial%20response%20%28with%20Set-Cookie%29%20to%20the%20browser%2C%20then%20perform%20the%20redirect%20on%20the%20client%20after%20the%20response%20is%20received.%0A%0AThe%20nextCookies%20plugin%20will%20only%20set%20cookies%20if%20the%20Set-Cookie%20header%20is%20present%20in%20the%20response%3B%20it%20cannot%20set%20cookies%20if%20you%20skip%20straight%20to%20a%20redirect%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/better-auth/src/integrations/next-js.ts%23L24-L85%29.%0A%0AFor%20Next.js%2C%20make%20sure%20nextCookies%20is%20the%20last%20plugin%20in%20your%20array%2C%20and%20avoid%20triggering%20sign-in%20flows%20from%20server%20components%E2%80%94use%20server%20actions%20or%20API%20routes%20instead%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/integrations/next.mdx%23L93-L375%29.%0A%0AIn%20summary%3A%20let%20the%20browser%20process%20the%20Set-Cookie%20header%20from%20the%20signInSocial%20response%20before%20redirecting.%20If%20you%20perform%20a%20server-side%20redirect%20before%20the%20response%20is%20sent%2C%20the%20state%20cookie%20will%20not%20be%20set%20and%20the%20OAuth%20flow%20will%20break%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/issues/5563%29.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6544)
Author
Owner

@gfrn commented on GitHub (Dec 5, 2025):

@dosubot signInSocial does not return a response with cookies, nor are they set. Is there no alternative which does not require me to call signInSocial from the client?

<!-- gh-comment-id:3616998618 --> @gfrn commented on GitHub (Dec 5, 2025): @dosubot signInSocial does not return a response with cookies, nor are they set. Is there no alternative which does not require me to call signInSocial from the client?
Author
Owner

@dosubot[bot] commented on GitHub (Dec 5, 2025):

There isn't a supported way to initiate social/OAuth sign-in from the backend that will set the necessary state cookie for the OAuth flow—this is a limitation of both Better Auth and frameworks like Next.js. The state cookie is set in the response to the client when you call signInSocial, and if you trigger a server-side redirect before the response (with Set-Cookie) reaches the browser, the cookie is never set, which breaks the OAuth flow and causes errors like please_restart_the_process reference.

The only reliable approach is to initiate the OAuth flow from the client using authClient.signIn.social. If you want to keep as much logic on the server as possible, you can create an API route that calls signInSocial, forwards the Set-Cookie headers to the browser, and then performs the redirect on the client after the response is received—this ensures the browser processes the cookie before navigation reference.

There are no lower-level APIs or workarounds to set the OAuth state cookie purely from the backend. This requirement was introduced in Better Auth v1.3.23+ for security and consistency reasons reference.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3617027107 --> @dosubot[bot] commented on GitHub (Dec 5, 2025): <!-- Answer --> There isn't a supported way to initiate social/OAuth sign-in from the backend that will set the necessary state cookie for the OAuth flow—this is a limitation of both Better Auth and frameworks like Next.js. The state cookie is set in the response to the client when you call signInSocial, and if you trigger a server-side redirect before the response (with Set-Cookie) reaches the browser, the cookie is never set, which breaks the OAuth flow and causes errors like please_restart_the_process [reference](https://github.com/better-auth/better-auth/issues/5055). The only reliable approach is to initiate the OAuth flow from the client using authClient.signIn.social. If you want to keep as much logic on the server as possible, you can create an API route that calls signInSocial, forwards the Set-Cookie headers to the browser, and then performs the redirect on the client after the response is received—this ensures the browser processes the cookie before navigation [reference](https://github.com/better-auth/better-auth/issues/2434). There are no lower-level APIs or workarounds to set the OAuth state cookie purely from the backend. This requirement was introduced in Better Auth v1.3.23+ for security and consistency reasons [reference](https://github.com/better-auth/better-auth/issues/5055). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/1ebe2647-8216-4858-b653-4550dedd3696?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=There%20isn%27t%20a%20supported%20way%20to%20initiate%20social/OAuth%20sign-in%20from%20the%20backend%20that%20will%20set%20the%20necessary%20state%20cookie%20for%20the%20OAuth%20flow%E2%80%94this%20is%20a%20limitation%20of%20both%20Better%20Auth%20and%20frameworks%20like%20Next.js.%20The%20state%20cookie%20is%20set%20in%20the%20response%20to%20the%20client%20when%20you%20call%20signInSocial%2C%20and%20if%20you%20trigger%20a%20server-side%20redirect%20before%20the%20response%20%28with%20Set-Cookie%29%20reaches%20the%20browser%2C%20the%20cookie%20is%20never%20set%2C%20which%20breaks%20the%20OAuth%20flow%20and%20causes%20errors%20like%20please_restart_the_process%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/issues/5055%29.%0A%0AThe%20only%20reliable%20approach%20is%20to%20initiate%20the%20OAuth%20flow%20from%20the%20client%20using%20authClient.signIn.social.%20If%20you%20want%20to%20keep%20as%20much%20logic%20on%20the%20server%20as%20possible%2C%20you%20can%20create%20an%20API%20route%20that%20calls%20signInSocial%2C%20forwards%20the%20Set-Cookie%20headers%20to%20the%20browser%2C%20and%20then%20performs%20the%20redirect%20on%20the%20client%20after%20the%20response%20is%20received%E2%80%94this%20ensures%20the%20browser%20processes%20the%20cookie%20before%20navigation%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/issues/2434%29.%0A%0AThere%20are%20no%20lower-level%20APIs%20or%20workarounds%20to%20set%20the%20OAuth%20state%20cookie%20purely%20from%20the%20backend.%20This%20requirement%20was%20introduced%20in%20Better%20Auth%20v1.3.23%2B%20for%20security%20and%20consistency%20reasons%C2%A0%5Breference%5D%28https%3A//github.com/better-auth/better-auth/issues/5055%29.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6544)
Author
Owner

@gfrn commented on GitHub (Dec 5, 2025):

@dosubot in which case, is there any chance I can perform a token exchange with a refresh token using the genericOAuth2 plugin? If so, how?

<!-- gh-comment-id:3617215863 --> @gfrn commented on GitHub (Dec 5, 2025): @dosubot in which case, is there any chance I can perform a token exchange with a refresh token using the genericOAuth2 plugin? If so, how?
Author
Owner

@dosubot[bot] commented on GitHub (Dec 5, 2025):

Yes, you can perform a token exchange with a refresh token using the genericOAuth2 plugin. Each provider instance exposes a refreshAccessToken method that calls the provider’s token endpoint with grant_type=refresh_token, using your client credentials and refresh token. To ensure you receive a refresh token, set accessType: "offline" in your provider config during the initial authorization flow docs.

Here’s a basic example of how to use it:

const provider = /* get your genericOAuth provider instance */;
const tokens = await provider.refreshAccessToken(refreshToken);
// tokens will include accessToken, refreshToken, etc.

The method dynamically determines the token endpoint from your config or discoveryUrl and handles authentication (Basic or POST) as required source.

A few caveats: your OAuth provider must actually issue refresh tokens, and for production, persistent storage is recommended to manage sessions and tokens. Stateless setups may not support refresh flows out of the box thread.

If you need a custom refresh flow, you can override the token exchange logic using the getToken option in your provider config docs.

Let me know if you want a more detailed code sample or have a specific provider in mind!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3617238484 --> @dosubot[bot] commented on GitHub (Dec 5, 2025): <!-- Answer --> Yes, you can perform a token exchange with a refresh token using the genericOAuth2 plugin. Each provider instance exposes a refreshAccessToken method that calls the provider’s token endpoint with grant_type=refresh_token, using your client credentials and refresh token. To ensure you receive a refresh token, set accessType: "offline" in your provider config during the initial authorization flow [docs](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/plugins/generic-oauth.mdx#L6-L353). Here’s a basic example of how to use it: ```typescript const provider = /* get your genericOAuth provider instance */; const tokens = await provider.refreshAccessToken(refreshToken); // tokens will include accessToken, refreshToken, etc. ``` The method dynamically determines the token endpoint from your config or discoveryUrl and handles authentication (Basic or POST) as required [source](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/core/src/oauth2/refresh-access-token.ts#L5-L124). A few caveats: your OAuth provider must actually issue refresh tokens, and for production, persistent storage is recommended to manage sessions and tokens. Stateless setups may not support refresh flows out of the box [thread](https://github.com/better-auth/better-auth/issues/2202). If you need a custom refresh flow, you can override the token exchange logic using the getToken option in your provider config [docs](https://github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/plugins/generic-oauth.mdx#L6-L353). Let me know if you want a more detailed code sample or have a specific provider in mind! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/8101cd84-f8bc-42f7-834d-018df76bfc3a?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Yes%2C%20you%20can%20perform%20a%20token%20exchange%20with%20a%20refresh%20token%20using%20the%20genericOAuth2%20plugin.%20Each%20provider%20instance%20exposes%20a%20refreshAccessToken%20method%20that%20calls%20the%20provider%E2%80%99s%20token%20endpoint%20with%20grant_type%3Drefresh_token%2C%20using%20your%20client%20credentials%20and%20refresh%20token.%20To%20ensure%20you%20receive%20a%20refresh%20token%2C%20set%20accessType%3A%20%22offline%22%20in%20your%20provider%20config%20during%20the%20initial%20authorization%20flow%C2%A0%5Bdocs%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/plugins/generic-oauth.mdx%23L6-L353%29.%0A%0AHere%E2%80%99s%20a%20basic%20example%20of%20how%20to%20use%20it%3A%0A%0A%60%60%60typescript%0Aconst%20provider%20%3D%20/%2A%20get%20your%20genericOAuth%20provider%20instance%20%2A/%3B%0Aconst%20tokens%20%3D%20await%20provider.refreshAccessToken%28refreshToken%29%3B%0A//%20tokens%20will%20include%20accessToken%2C%20refreshToken%2C%20etc.%0A%60%60%60%0A%0AThe%20method%20dynamically%20determines%20the%20token%20endpoint%20from%20your%20config%20or%20discoveryUrl%20and%20handles%20authentication%20%28Basic%20or%20POST%29%20as%20required%C2%A0%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/packages/core/src/oauth2/refresh-access-token.ts%23L5-L124%29.%0A%0AA%20few%20caveats%3A%20your%20OAuth%20provider%20must%20actually%20issue%20refresh%20tokens%2C%20and%20for%20production%2C%20persistent%20storage%20is%20recommended%20to%20manage%20sessions%20and%20tokens.%20Stateless%20setups%20may%20not%20support%20refresh%20flows%20out%20of%20the%20box%C2%A0%5Bthread%5D%28https%3A//github.com/better-auth/better-auth/issues/2202%29.%0A%0AIf%20you%20need%20a%20custom%20refresh%20flow%2C%20you%20can%20override%20the%20token%20exchange%20logic%20using%20the%20getToken%20option%20in%20your%20provider%20config%C2%A0%5Bdocs%5D%28https%3A//github.com/better-auth/better-auth/blob/015a5c4b660b69f2a941ffd069ea831c8670a45d/docs/content/docs/plugins/generic-oauth.mdx%23L6-L353%29.%0A%0ALet%20me%20know%20if%20you%20want%20a%20more%20detailed%20code%20sample%20or%20have%20a%20specific%20provider%20in%20mind%21)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6544)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10549