Plugin GenericOauth - refresh_token_expires_in never set on refreshAccessToken #2783

Closed
opened 2026-03-13 10:20:02 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @murdok12 on GitHub (Jan 29, 2026).

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I'm currently working with GenericOAuth plugin. My refresh token expires at is never updated on accounts database even when my IDP server send "refresh_token_expires_in".
When the user is logged in, the accounts.refreshTokenExpiresAt is set but never updated.

To reproduce :

    1. Log in with OAuthClient that exposes "refresh_token_expires_in" in /token
    1. Check that the refreshTokenExpiresAt has been set
    1. Wait the accessToken to expire
    1. Refresh your database, the refreshTokenExpiresAt is not updated

In refreshAccessToken method there is no such code :

if (data.refresh_token_expires_in) { const now = Date.now(); tokens.refreshTokenExpiresAt = new Date(now + data.refresh_token_expires_in * 1_000); }

Once I've tested those lines, the refreshTokenExpiresAt is updated.

Current vs. Expected behavior

Example : First refresh token expires at 12:30AM
Second refresh token expires at 1:00PM

Current : 12:30AM
Expected : refreshTokenExpiresAt = 1:00PM

What version of Better Auth are you using?

1.4.18

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.2.0: Tue Nov 18 21:07:05 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6020",
    "release": "25.2.0",
    "cpuCount": 12,
    "cpuModel": "Apple M2 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.29 GB"
  },
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "yarn",
    "version": "4.6.0"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^15"
    },
    {
      "name": "react",
      "version": "^19.1.0"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^6.18.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.17",
    "config": {
      "plugins": [
        {
          "name": "generic-oauth",
          "config": {
            "id": "generic-oauth",
            "endpoints": {},
            "options": {
              "config": [
                {
                  "providerId": "my-idp-id",
                  "clientId": "[REDACTED]",
                  "clientSecret": "[REDACTED]",
                  "discoveryUrl": "http://localhost:3001/.well-known/openid-configuration",
                  "pkce": true
                }
              ]
            },
            "$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"
            }
          }
        }
      ],
      "onAPIError": {
        "errorURL": "/auth/v1/login"
      },
      "account": {
        "updateAccountOnSignIn": true,
        "accountLinking": {
          "enabled": true,
          "trustedProviders": [
            "my-idp-id"
          ]
        }
      },
      "trustedOrigins": [
        "http://localhost:4000",
        "http://localhost:3001"
      ],
      "advanced": {
        "database": {
          "generateId": "uuid"
        }
      }
    }
  }
}

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

Package

Auth config (if applicable)

export const auth = betterAuth({
    database: prismaAdapter(prisma, {
        provider: 'postgresql',
    }),
    plugins: [
        genericOAuth({
            config: [
                {
                    providerId: process.env.OAUTH_CLIENT_ID as string,
                    clientId: process.env.OAUTH_CLIENT_ID as string,
                    clientSecret: process.env.OAUTH_CLIENT_SECRET as string,
                    discoveryUrl:
                        `${process.env.IDP_ENDPOINT}/.well-known/openid-configuration` as string,
                    pkce: true,
                },
            ],
        }),
    ],
    onAPIError: {
        errorURL: AUTH_LOGIN_ROUTE,
    },
    account: {
        updateAccountOnSignIn: true,
        accountLinking: {
            enabled: true,
            trustedProviders: [process.env.OAUTH_CLIENT_ID as string],
        },
    },
    trustedOrigins: [process.env.DOMAIN_NAME as string, process.env.IDP_ENDPOINT as string],
    advanced: {
        database: {
            generateId: 'uuid',
        },
    },
});

Additional context

No response

Originally created by @murdok12 on GitHub (Jan 29, 2026). Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I'm currently working with GenericOAuth plugin. My refresh token expires at is never updated on accounts database even when my IDP server send "refresh_token_expires_in". When the user is logged in, the accounts.refreshTokenExpiresAt is set but never updated. To reproduce : - 1. Log in with OAuthClient that exposes "refresh_token_expires_in" in /token - 2. Check that the refreshTokenExpiresAt has been set - 3. Wait the accessToken to expire - 4. Refresh your database, the refreshTokenExpiresAt is not updated In refreshAccessToken method there is no such code : `if (data.refresh_token_expires_in) { const now = Date.now(); tokens.refreshTokenExpiresAt = new Date(now + data.refresh_token_expires_in * 1_000); }` Once I've tested those lines, the refreshTokenExpiresAt is updated. ### Current vs. Expected behavior Example : First refresh token expires at 12:30AM Second refresh token expires at 1:00PM Current : 12:30AM Expected : refreshTokenExpiresAt = 1:00PM ### What version of Better Auth are you using? 1.4.18 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.2.0: Tue Nov 18 21:07:05 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6020", "release": "25.2.0", "cpuCount": 12, "cpuModel": "Apple M2 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.29 GB" }, "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "yarn", "version": "4.6.0" }, "frameworks": [ { "name": "next", "version": "^15" }, { "name": "react", "version": "^19.1.0" } ], "databases": [ { "name": "@prisma/client", "version": "^6.18.0" } ], "betterAuth": { "version": "^1.4.17", "config": { "plugins": [ { "name": "generic-oauth", "config": { "id": "generic-oauth", "endpoints": {}, "options": { "config": [ { "providerId": "my-idp-id", "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "discoveryUrl": "http://localhost:3001/.well-known/openid-configuration", "pkce": true } ] }, "$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" } } } ], "onAPIError": { "errorURL": "/auth/v1/login" }, "account": { "updateAccountOnSignIn": true, "accountLinking": { "enabled": true, "trustedProviders": [ "my-idp-id" ] } }, "trustedOrigins": [ "http://localhost:4000", "http://localhost:3001" ], "advanced": { "database": { "generateId": "uuid" } } } } } ``` ### Which area(s) are affected? (Select all that apply) Package ### Auth config (if applicable) ```typescript export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'postgresql', }), plugins: [ genericOAuth({ config: [ { providerId: process.env.OAUTH_CLIENT_ID as string, clientId: process.env.OAUTH_CLIENT_ID as string, clientSecret: process.env.OAUTH_CLIENT_SECRET as string, discoveryUrl: `${process.env.IDP_ENDPOINT}/.well-known/openid-configuration` as string, pkce: true, }, ], }), ], onAPIError: { errorURL: AUTH_LOGIN_ROUTE, }, account: { updateAccountOnSignIn: true, accountLinking: { enabled: true, trustedProviders: [process.env.OAUTH_CLIENT_ID as string], }, }, trustedOrigins: [process.env.DOMAIN_NAME as string, process.env.IDP_ENDPOINT as string], advanced: { database: { generateId: 'uuid', }, }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 10:20:02 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 29, 2026):

It seems you are facing an issue where the refresh_token_expires_in value from your Identity Provider (IDP) is not updating the refreshTokenExpiresAt in your database when using the GenericOAuth plugin. This behavior can be unexpected if the token's expiration information is supposed to be managed dynamically.

From what you've described and the context provided, it looks like there’s a need for code implementation in the refreshAccessToken method to handle the refresh_token_expires_in value properly. This code should ideally look something like this:

if (data.refresh_token_expires_in) {
    const now = Date.now();
    tokens.refreshTokenExpiresAt = new Date(now + data.refresh_token_expires_in * 1_000);
}

This would ensure that every time a token is refreshed, the expiration date is updated in your application’s database.

Currently, there’s an open issue discussing adding support for refreshTokenParams, which may further help in passing necessary parameters when refreshing tokens. It has been noted that right now, the implementation lacks the extra parameters that some OAuth providers might require during the refresh token flow [3].

As a next step, you may want to consider implementing that suggested code snippet and checking if it resolves your issue. If you continue to face problems after making this change, please tag @bekacru or @ping__ to get more specialized assistance.

Do you see any potential issues with implementing that code, or do you have any other questions about Better Auth?

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

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Jan 29, 2026): It seems you are facing an issue where the `refresh_token_expires_in` value from your Identity Provider (IDP) is not updating the `refreshTokenExpiresAt` in your database when using the GenericOAuth plugin. This behavior can be unexpected if the token's expiration information is supposed to be managed dynamically. From what you've described and the context provided, it looks like there’s a need for code implementation in the `refreshAccessToken` method to handle the `refresh_token_expires_in` value properly. This code should ideally look something like this: ```typescript if (data.refresh_token_expires_in) { const now = Date.now(); tokens.refreshTokenExpiresAt = new Date(now + data.refresh_token_expires_in * 1_000); } ``` This would ensure that every time a token is refreshed, the expiration date is updated in your application’s database. Currently, there’s an open issue discussing adding support for `refreshTokenParams`, which may further help in passing necessary parameters when refreshing tokens. It has been noted that right now, the implementation lacks the extra parameters that some OAuth providers might require during the refresh token flow [[3]](https://github.com/better-auth/better-auth/issues/7554). As a next step, you may want to consider implementing that suggested code snippet and checking if it resolves your issue. If you continue to face problems after making this change, please tag @bekacru or @ping__ to get more specialized assistance. Do you see any potential issues with implementing that code, or do you have any other questions about Better Auth? _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/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@bytaesu commented on GitHub (Feb 5, 2026):

Hi @murdok12, I'm checking this

@bytaesu commented on GitHub (Feb 5, 2026): Hi @murdok12, I'm checking this
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2783