The access token returned by auth.api.getAccessToken for the Cognito provider is not automatically refreshed when it expires #3034

Open
opened 2026-03-13 10:35:34 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @matteocollina on GitHub (Mar 12, 2026).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Execute the call to get the access token:

    const session = await auth.api.getAccessToken({
      body: {
        providerId: "cognito",
      },
      headers: await headers(),
    });
    
  2. After the call succeeds, you expect to receive a valid access_token.

  3. Currently, the access token is not automatically refreshed when it expires.

Current vs. Expected behavior

The access token returned by the call is not automatically refreshed when it expires, and it's unclear how to retrieve the refresh_token to handle refreshing manually.

What version of Better Auth are you using?

1.4.18

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6020",
    "release": "24.6.0",
    "cpuCount": 12,
    "cpuModel": "Apple M2 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.20 GB"
  },
  "node": {
    "version": "v22.13.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.1.6"
    },
    {
      "name": "react",
      "version": "19.2.3"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.4.18",
    "config": {
      "appName": "Doublew",
      "secret": "[REDACTED]",
      "socialProviders": {
        "cognito": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "domain": "dw-be-dev.auth.eu-central-1.amazoncognito.com",
          "region": "eu-central-1",
          "userPoolId": "eu-central-1_lW7LaR6Lv"
        }
      },
      "session": {
        "expiresIn": 604800,
        "cookieCache": {
          "enabled": true,
          "maxAge": 2592000,
          "strategy": "jwt",
          "refreshCache": true
        }
      },
      "account": {
        "storeStateStrategy": "cookie",
        "storeAccountCookie": true
      },
      "plugins": [
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        }
      ]
    }
  }
}

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

Client

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

const betterAuthSecret = process.env.BETTER_AUTH_SECRET;
if (!betterAuthSecret) {
  throw new Error("Missing BETTER_AUTH_SECRET environment variable");
}

export const auth = betterAuth({
  appName: "MyApp",
  secret: betterAuthSecret,
  socialProviders: {
    cognito: {
      clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID as string,
      clientSecret: process.env.COGNITO_CLIENT_SECRET as string,
      domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN as string,
      region: process.env.COGNITO_REGION as string,
      userPoolId: process.env.COGNITO_USERPOOL_ID as string,
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    cookieCache: {
      enabled: true,
      maxAge: 30 * 24 * 60 * 60, // 30 days
      strategy: "jwt", // or "compact" or "jwe"
      refreshCache: true, // enables fully stateless mode
    },
  },
  account: {
    storeStateStrategy: "cookie",
    storeAccountCookie: true,
  },
  plugins: [nextCookies()],
})

Additional context

No response

Originally created by @matteocollina on GitHub (Mar 12, 2026). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Execute the call to get the access token: ```javascript const session = await auth.api.getAccessToken({ body: { providerId: "cognito", }, headers: await headers(), }); ``` 2. After the call succeeds, you expect to receive a valid `access_token`. 3. Currently, the access token is not automatically refreshed when it expires. ### Current vs. Expected behavior The access token returned by the call is not automatically refreshed when it expires, and it's unclear how to retrieve the `refresh_token` to handle refreshing manually. ### What version of Better Auth are you using? 1.4.18 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6020", "release": "24.6.0", "cpuCount": 12, "cpuModel": "Apple M2 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.20 GB" }, "node": { "version": "v22.13.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "next", "version": "16.1.6" }, { "name": "react", "version": "19.2.3" } ], "databases": null, "betterAuth": { "version": "^1.4.18", "config": { "appName": "Doublew", "secret": "[REDACTED]", "socialProviders": { "cognito": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "domain": "dw-be-dev.auth.eu-central-1.amazoncognito.com", "region": "eu-central-1", "userPoolId": "eu-central-1_lW7LaR6Lv" } }, "session": { "expiresIn": 604800, "cookieCache": { "enabled": true, "maxAge": 2592000, "strategy": "jwt", "refreshCache": true } }, "account": { "storeStateStrategy": "cookie", "storeAccountCookie": true }, "plugins": [ { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { nextCookies } from "better-auth/next-js"; const betterAuthSecret = process.env.BETTER_AUTH_SECRET; if (!betterAuthSecret) { throw new Error("Missing BETTER_AUTH_SECRET environment variable"); } export const auth = betterAuth({ appName: "MyApp", secret: betterAuthSecret, socialProviders: { cognito: { clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID as string, clientSecret: process.env.COGNITO_CLIENT_SECRET as string, domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN as string, region: process.env.COGNITO_REGION as string, userPoolId: process.env.COGNITO_USERPOOL_ID as string, }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days cookieCache: { enabled: true, maxAge: 30 * 24 * 60 * 60, // 30 days strategy: "jwt", // or "compact" or "jwe" refreshCache: true, // enables fully stateless mode }, }, account: { storeStateStrategy: "cookie", storeAccountCookie: true, }, plugins: [nextCookies()], }) ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 10:35:34 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 12, 2026):

This is a known issue with Better Auth's stateless OAuth mode, especially with Cognito. The getAccessToken method is designed to auto-refresh expired tokens, but there are several issues that can prevent this from working:

Most likely cause - Cookie size limit: Cognito returns three large JWT tokens (accessToken, refreshToken, idToken) that collectively exceed the browser's ~4KB cookie size limit. When the account_data cookie fails to be set, getAccessToken can't find the account data needed for refresh.

Other possible causes:

Recommended solutions:

  1. Use database-backed storage (most reliable) - Community consensus is that pure stateless OAuth isn't production-ready yet:
export const auth = betterAuth({
  database: yourDbAdapter({ /* ... */ }),
  account: {
    storeAccountCookie: false,
  },
});
  1. Use the explicit /refresh-token endpoint instead of relying on auto-refresh:
const result = await client.$fetch("/refresh-token", {
  method: "POST",
  body: { providerId: "cognito" }
});
// Returns both accessToken and refreshToken
  1. Implement custom refresh logic if needed:
socialProviders: {
  cognito: {
    // ... your config
    refreshAccessToken: async (refreshToken) => {
      // Custom refresh implementation
      return { accessToken: "new-token", refreshToken: "new-refresh" };
    },
  },
}

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

@dosubot[bot] commented on GitHub (Mar 12, 2026): <!-- Answer --> This is a known issue with Better Auth's stateless OAuth mode, especially with Cognito. The [`getAccessToken` method is designed to auto-refresh expired tokens](https://github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/better-auth/src/api/routes/account.ts#L547-L582), but there are several issues that can prevent this from working: **Most likely cause - Cookie size limit**: [Cognito returns three large JWT tokens (accessToken, refreshToken, idToken) that collectively exceed the browser's ~4KB cookie size limit](https://github.com/better-auth/better-auth/issues/6379). When the `account_data` cookie fails to be set, `getAccessToken` can't find the account data needed for refresh. **Other possible causes**: - [A bug exists where providers that don't return a new refresh_token in their refresh response have the original refresh token overwritten with `undefined`](https://github.com/better-auth/better-auth/issues/7999) - [In Next.js Server Components, `Set-Cookie` headers can be silently dropped during streaming](https://github.com/better-auth/better-auth/issues/7394) **Recommended solutions**: 1. **Use database-backed storage** (most reliable) - [Community consensus is that pure stateless OAuth isn't production-ready yet](https://github.com/better-auth/better-auth/discussions/6715): ```typescript export const auth = betterAuth({ database: yourDbAdapter({ /* ... */ }), account: { storeAccountCookie: false, }, }); ``` 2. **Use the explicit `/refresh-token` endpoint** instead of relying on auto-refresh: ```typescript const result = await client.$fetch("/refresh-token", { method: "POST", body: { providerId: "cognito" } }); // Returns both accessToken and refreshToken ``` 3. **Implement custom refresh logic** if needed: ```typescript socialProviders: { cognito: { // ... your config refreshAccessToken: async (refreshToken) => { // Custom refresh implementation return { accessToken: "new-token", refreshToken: "new-refresh" }; }, }, } ``` <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=brand-link).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=great_response&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=irrelevant_answer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=incorrect_sources&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=too_verbose&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=hallucination&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=bug_report&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-bug_report) | [Other](https://app.dosu.dev/response-feedback/bf73e818-9443-4b05-b006-411df4186a2e?feedback_type=other&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-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&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=chat-badge)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20issue%20with%20Better%20Auth%27s%20stateless%20OAuth%20mode%2C%20especially%20with%20Cognito.%20The%20%5B%60getAccessToken%60%20method%20is%20designed%20to%20auto-refresh%20expired%20tokens%5D%28https%3A//github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/better-auth/src/api/routes/account.ts%23L547-L582%29%2C%20but%20there%20are%20several%20issues%20that%20can%20prevent%20this%20from%20working%3A%0A%0A%2A%2AMost%20likely%20cause%20-%20Cookie%20size%20limit%2A%2A%3A%20%5BCognito%20returns%20three%20large%20JWT%20tokens%20%28accessToken%2C%20refreshToken%2C%20idToken%29%20that%20collectively%20exceed%20the%20browser%27s%20~4KB%20cookie%20size%20limit%5D%28https%3A//github.com/better-auth/better-auth/issues/6379%29.%20When%20the%20%60account_data%60%20cookie%20fails%20to%20be%20set%2C%20%60getAccessToken%60%20can%27t%20find%20the%20account%20data%20needed%20for%20refresh.%0A%0A%2A%2AOther%20possible%20causes%2A%2A%3A%0A-%20%5BA%20bug%20exists%20where%20providers%20that%20don%27t%20return%20a%20new%20refresh_token%20in%20their%20refresh%20response%20have%20the%20original%20refresh%20token%20overwritten%20with%20%60undefined%60%5D%28https%3A//github.com/better-auth/better-auth/issues/7999%29%0A-%20%5BIn%20Next.js%20Server%20Components%2C%20%60Set-Cookie%60%20headers%20can%20be%20silently%20dropped%20during%20streaming%5D%28https%3A//github.com/better-auth/better-auth/issues/7394%29%0A%0A%2A%2ARecommended%20solutions%2A%2A%3A%0A%0A1.%20%2A%2AUse%20database-backed%20storage%2A%2A%20%28most%20reliable%29%20-%20%5BCommunity%20consensus%20is%20that%20pure%20stateless%20OAuth%20isn%27t%20production-ready%20yet%5D%28https%3A//github.com/better-auth/better-auth/discussions/6715%29%3A%0A%60%60%60typescript%0Aexport%20const%20auth%20%3D%20betterAuth%28%7B%0A%20%20database%3A%20yourDbAdapter%28%7B%20/%2A%20...%20%2A/%20%7D%29%2C%0A%20%20account%3A%20%7B%0A%20%20%20%20storeAccountCookie%3A%20false%2C%0A%20%20%7D%2C%0A%7D%29%3B%0A%60%60%60%0A%0A2.%20%2A%2AUse%20the%20explicit%20%60/refresh-token%60%20endpoint%2A%2A%20instead%20of%20relying%20on%20auto-refresh%3A%0A%60%60%60typescript%0Aconst%20result%20%3D%20await%20client.%24fetch%28%22/refresh-token%22%2C%20%7B%0A%20%20method%3A%20%22POST%22%2C%0A%20%20body%3A%20%7B%20providerId%3A%20%22cognito%22%20%7D%0A%7D%29%3B%0A//%20Returns%20both%20accessToken%20and%20refreshToken%0A%60%60%60%0A%0A3.%20%2A%2AImplement%20custom%20refresh%20logic%2A%2A%20if%20needed%3A%0A%60%60%60typescript%0AsocialProviders%3A%20%7B%0A%20%20cognito%3A%20%7B%0A%20%20%20%20//%20...%20your%20config%0A%20%20%20%20refreshAccessToken%3A%20async%20%28refreshToken%29%20%3D%3E%20%7B%0A%20%20%20%20%20%20//%20Custom%20refresh%20implementation%0A%20%20%20%20%20%20return%20%7B%20accessToken%3A%20%22new-token%22%2C%20refreshToken%3A%20%22new-refresh%22%20%7D%3B%0A%20%20%20%20%7D%2C%0A%20%20%7D%2C%0A%7D%0A%60%60%60)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=join-discord)&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/8562)
Author
Owner

@matteocollina commented on GitHub (Mar 12, 2026):

@dosu, I don't want to use a dbAdapter for storage. Implementing custom refresh logic is fine, but the problem is that only the accessToken and idToken are passed, not the refreshToken. How should I handle this in my custom refresh implementation?

@matteocollina commented on GitHub (Mar 12, 2026): @dosu, I don't want to use a dbAdapter for storage. Implementing custom refresh logic is fine, but the problem is that only the accessToken and idToken are passed, not the refreshToken. How should I handle this in my custom refresh implementation?
Author
Owner

@dosubot[bot] commented on GitHub (Mar 12, 2026):

The custom refreshAccessToken function should actually receive the refreshToken as its only parameter—not accessToken and idToken. The function signature is defined as:

refreshAccessToken?: (refreshToken: string) => Promise<OAuth2Tokens>

When Better Auth calls your custom function, it retrieves the stored refresh token, decrypts it if needed, and passes it directly to your implementation.

Example implementation:

socialProviders: {
  cognito: {
    // ... your config
    refreshAccessToken: async (refreshToken) => {
      // refreshToken is passed directly as the parameter
      const response = await fetch('https://your-cognito-domain/oauth2/token', {
        method: 'POST',
        body: new URLSearchParams({
          grant_type: 'refresh_token',
          refresh_token: refreshToken,
          client_id: process.env.COGNITO_CLIENT_ID,
        })
      });
      const data = await response.json();
      return {
        accessToken: data.access_token,
        refreshToken: data.refresh_token || refreshToken, // Important: preserve original if not returned
        accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1000),
      };
    },
  },
}

Important: There's a known bug where the refresh token gets overwritten with undefined if you don't return it from your custom function. Always return refreshToken: data.refresh_token || refreshToken to preserve the original.

If you're not receiving the refresh token as expected, could you share more about where you're seeing that only accessToken/idToken are passed? That would help narrow down if there's a different issue at play.

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

@dosubot[bot] commented on GitHub (Mar 12, 2026): <!-- Answer --> The custom `refreshAccessToken` function should actually receive the `refreshToken` as its only parameter—not `accessToken` and `idToken`. [The function signature is defined as](https://github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/core/src/oauth2/oauth-provider.ts#L69-L71): ```typescript refreshAccessToken?: (refreshToken: string) => Promise<OAuth2Tokens> ``` [When Better Auth calls your custom function, it retrieves the stored refresh token, decrypts it if needed, and passes it directly to your implementation](https://github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/better-auth/src/api/routes/account.ts#L750-L756). Example implementation: ```typescript socialProviders: { cognito: { // ... your config refreshAccessToken: async (refreshToken) => { // refreshToken is passed directly as the parameter const response = await fetch('https://your-cognito-domain/oauth2/token', { method: 'POST', body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, client_id: process.env.COGNITO_CLIENT_ID, }) }); const data = await response.json(); return { accessToken: data.access_token, refreshToken: data.refresh_token || refreshToken, // Important: preserve original if not returned accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1000), }; }, }, } ``` **Important**: There's a [known bug where the refresh token gets overwritten with `undefined`](https://github.com/better-auth/better-auth/issues/7999) if you don't return it from your custom function. Always return `refreshToken: data.refresh_token || refreshToken` to preserve the original. If you're not receiving the refresh token as expected, could you share more about where you're seeing that only accessToken/idToken are passed? That would help narrow down if there's a different issue at play. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=brand-link).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=great_response&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=irrelevant_answer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=incorrect_sources&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=too_verbose&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=hallucination&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=bug_report&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-bug_report) | [Other](https://app.dosu.dev/response-feedback/d08df463-2729-4200-810b-66c0905afb81?feedback_type=other&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-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&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=chat-badge)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20custom%20%60refreshAccessToken%60%20function%20should%20actually%20receive%20the%20%60refreshToken%60%20as%20its%20only%20parameter%E2%80%94not%20%60accessToken%60%20and%20%60idToken%60.%20%5BThe%20function%20signature%20is%20defined%20as%5D%28https%3A//github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/core/src/oauth2/oauth-provider.ts%23L69-L71%29%3A%0A%0A%60%60%60typescript%0ArefreshAccessToken%3F%3A%20%28refreshToken%3A%20string%29%20%3D%3E%20Promise%3COAuth2Tokens%3E%0A%60%60%60%0A%0A%5BWhen%20Better%20Auth%20calls%20your%20custom%20function%2C%20it%20retrieves%20the%20stored%20refresh%20token%2C%20decrypts%20it%20if%20needed%2C%20and%20passes%20it%20directly%20to%20your%20implementation%5D%28https%3A//github.com/better-auth/better-auth/blob/db5a44424f5747c47a7da347613e42b664e1e734/packages/better-auth/src/api/routes/account.ts%23L750-L756%29.%0A%0AExample%20implementation%3A%0A%60%60%60typescript%0AsocialProviders%3A%20%7B%0A%20%20cognito%3A%20%7B%0A%20%20%20%20//%20...%20your%20config%0A%20%20%20%20refreshAccessToken%3A%20async%20%28refreshToken%29%20%3D%3E%20%7B%0A%20%20%20%20%20%20//%20refreshToken%20is%20passed%20directly%20as%20the%20parameter%0A%20%20%20%20%20%20const%20response%20%3D%20await%20fetch%28%27https%3A//your-cognito-domain/oauth2/token%27%2C%20%7B%0A%20%20%20%20%20%20%20%20method%3A%20%27POST%27%2C%0A%20%20%20%20%20%20%20%20body%3A%20new%20URLSearchParams%28%7B%0A%20%20%20%20%20%20%20%20%20%20grant_type%3A%20%27refresh_token%27%2C%0A%20%20%20%20%20%20%20%20%20%20refresh_token%3A%20refreshToken%2C%0A%20%20%20%20%20%20%20%20%20%20client_id%3A%20process.env.COGNITO_CLIENT_ID%2C%0A%20%20%20%20%20%20%20%20%7D%29%0A%20%20%20%20%20%20%7D%29%3B%0A%20%20%20%20%20%20const%20data%20%3D%20await%20response.json%28%29%3B%0A%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20accessToken%3A%20data.access_token%2C%0A%20%20%20%20%20%20%20%20refreshToken%3A%20data.refresh_token%20%7C%7C%20refreshToken%2C%20//%20Important%3A%20preserve%20original%20if%20not%20returned%0A%20%20%20%20%20%20%20%20accessTokenExpiresAt%3A%20new%20Date%28Date.now%28%29%20%2B%20data.expires_in%20%2A%201000%29%2C%0A%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%7D%2C%0A%20%20%7D%2C%0A%7D%0A%60%60%60%0A%0A%2A%2AImportant%2A%2A%3A%20There%27s%20a%20%5Bknown%20bug%20where%20the%20refresh%20token%20gets%20overwritten%20with%20%60undefined%60%5D%28https%3A//github.com/better-auth/better-auth/issues/7999%29%20if%20you%20don%27t%20return%20it%20from%20your%20custom%20function.%20Always%20return%20%60refreshToken%3A%20data.refresh_token%20%7C%7C%20refreshToken%60%20to%20preserve%20the%20original.%0A%0AIf%20you%27re%20not%20receiving%20the%20refresh%20token%20as%20expected%2C%20could%20you%20share%20more%20about%20where%20you%27re%20seeing%20that%20only%20accessToken/idToken%20are%20passed%3F%20That%20would%20help%20narrow%20down%20if%20there%27s%20a%20different%20issue%20at%20play.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=join-discord)&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/8562)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#3034