[GH-ISSUE #6486] authorizationUrlParams not being applied in genericOAuth plugin #19162

Closed
opened 2026-04-15 17:58:10 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @hdisma on GitHub (Dec 3, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6486

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Configure genericOAuth with authorizationUrlParams:
import { betterAuth } from "better-auth"
import { genericOAuth } from "better-auth/plugins/generic-oauth"

export const auth = betterAuth({
  baseURL: "http://localhost:3000",
  secret: "your-secret",
  plugins: [
    genericOAuth({
      config: [
        {
          providerId: "auth0",
          authorizationUrl: `https://dev-xxx.us.auth0.com/authorize`,
          tokenUrl: `https://dev-xxx.us.auth0.com/oauth/token`,
          userInfoUrl: `https://dev-xxx.us.auth0.com/userinfo`,
          clientId: "your-client-id",
          clientSecret: "your-client-secret",
          scopes: ["openid", "profile", "email"],
          authorizationUrlParams: {
            audience: "https://my-api/"
          },
        }
      ],
    }),
  ],
})
  1. On the client side, initiate the OAuth flow:
authClient.signIn.social({
  provider: "auth0",
  callbackURL: "/dashboard",
})
  1. Inspect the network request to /api/auth/sign-in/social
  2. Check the authorization URL in the response - the audience parameter is missing

Additional Testing

Also tested with function form:

authorizationUrlParams: (ctx) => {
  console.log('=== authorizationUrlParams called ==='); // Never logged
  return {
    audience: process.env.AUTH0_AUDIENCE
  };
}

The function is never called, indicating the parameter is not being processed at all.

Current vs. Expected behavior

Expected authorization URL:

https://dev-xxx.us.auth0.com/authorize?response_type=code&client_id=xxx&state=xxx&scope=openid+profile+email&redirect_uri=xxx&audience=https://my-api/

Actual Behavior

The audience parameter (and any other custom parameters) are not included in the authorization URL. Actual authorization URL:
https://dev-xxx.us.auth0.com/authorize?response_type=code&client_id=xxx&state=xxx&scope=openid+profile+email&redirect_uri=xxx

What version of Better Auth are you using?

1.4.5

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26200",
    "cpuCount": 22,
    "cpuModel": "Intel(R) Core(TM) Ultra 7 155H",
    "totalMemory": "31.52 GB",
    "freeMemory": "14.17 GB"
  },
  "node": {
    "version": "v22.13.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "^19.2.0"
    }
  ],
  "databases": [
    {
      "name": "better-sqlite3",
      "version": "^12.5.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.5",
    "config": {
      "baseURL": "http://localhost:3000",
      "secret": "[REDACTED]",
      "session": {
        "cookieCache": {
          "enabled": true,
          "maxAge": 604800,
          "strategy": "jwt",
          "refreshCache": true
        }
      },
      "account": {
        "storeStateStrategy": "cookie",
        "storeAccountCookie": true
      },
      "plugins": [
        {
          "name": "custom-session",
          "config": {
            "id": "custom-session",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$Infer": {
              "Session": {}
            }
          }
        },
        {
          "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"
            }
          }
        }
      ],
      "trustedOrigins": [
        "http://localhost:3000"
      ]
    }
  }
}

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

Backend, Client

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @hdisma on GitHub (Dec 3, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6486 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Configure genericOAuth with authorizationUrlParams: ```typescript import { betterAuth } from "better-auth" import { genericOAuth } from "better-auth/plugins/generic-oauth" export const auth = betterAuth({ baseURL: "http://localhost:3000", secret: "your-secret", plugins: [ genericOAuth({ config: [ { providerId: "auth0", authorizationUrl: `https://dev-xxx.us.auth0.com/authorize`, tokenUrl: `https://dev-xxx.us.auth0.com/oauth/token`, userInfoUrl: `https://dev-xxx.us.auth0.com/userinfo`, clientId: "your-client-id", clientSecret: "your-client-secret", scopes: ["openid", "profile", "email"], authorizationUrlParams: { audience: "https://my-api/" }, } ], }), ], }) ``` 2. On the client side, initiate the OAuth flow: ```typescript authClient.signIn.social({ provider: "auth0", callbackURL: "/dashboard", }) ``` 3. Inspect the network request to /api/auth/sign-in/social 4. Check the authorization URL in the response - the audience parameter is missing ### Additional Testing Also tested with function form: ```typescript authorizationUrlParams: (ctx) => { console.log('=== authorizationUrlParams called ==='); // Never logged return { audience: process.env.AUTH0_AUDIENCE }; } ``` The function is never called, indicating the parameter is not being processed at all. ### Current vs. Expected behavior ### Expected authorization URL: `https://dev-xxx.us.auth0.com/authorize?response_type=code&client_id=xxx&state=xxx&scope=openid+profile+email&redirect_uri=xxx&audience=https://my-api/` ### Actual Behavior The `audience` parameter (and any other custom parameters) are not included in the authorization URL. Actual authorization URL: `https://dev-xxx.us.auth0.com/authorize?response_type=code&client_id=xxx&state=xxx&scope=openid+profile+email&redirect_uri=xxx` ### What version of Better Auth are you using? 1.4.5 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26200", "cpuCount": 22, "cpuModel": "Intel(R) Core(TM) Ultra 7 155H", "totalMemory": "31.52 GB", "freeMemory": "14.17 GB" }, "node": { "version": "v22.13.1", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "react", "version": "^19.2.0" } ], "databases": [ { "name": "better-sqlite3", "version": "^12.5.0" } ], "betterAuth": { "version": "^1.4.5", "config": { "baseURL": "http://localhost:3000", "secret": "[REDACTED]", "session": { "cookieCache": { "enabled": true, "maxAge": 604800, "strategy": "jwt", "refreshCache": true } }, "account": { "storeStateStrategy": "cookie", "storeAccountCookie": true }, "plugins": [ { "name": "custom-session", "config": { "id": "custom-session", "hooks": { "after": [ {} ] }, "endpoints": {}, "$Infer": { "Session": {} } } }, { "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" } } } ], "trustedOrigins": [ "http://localhost:3000" ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend, Client ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-15 17:58:10 -05:00
Author
Owner

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

Hi there, thanks for opening this issue. We’ve noticed that in version 1.4.5 the genericOAuth plugin isn’t calling the authorizationUrlParams function, so any custom parameters (like audience) aren’t getting appended to the authorization URL. This appears to be a bug where the function isn’t invoked at all, which is why you’re not seeing your custom parameters reflected in the URL [1].

For troubleshooting, here are a couple of steps you could consider:
• Double-check that your configuration exactly matches the expected format for the genericOAuth plugin.
• As a temporary workaround, you might try manually appending the required parameters to the authorizationUrl if that’s feasible for your setup.
• We’re actively investigating the issue to have a proper fix included in a future release.

Does this workaround help your current setup, or do you have any additional details that might assist further? Tag @better-auth-agent if you would like an answer from the Agent.

If you need more help, tag @Skyvern in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3605257165 --> @better-auth-agent[bot] commented on GitHub (Dec 3, 2025): Hi there, thanks for opening this issue. We’ve noticed that in version 1.4.5 the genericOAuth plugin isn’t calling the authorizationUrlParams function, so any custom parameters (like audience) aren’t getting appended to the authorization URL. This appears to be a bug where the function isn’t invoked at all, which is why you’re not seeing your custom parameters reflected in the URL [[1]](https://github.com/better-auth/better-auth/issues/6446). For troubleshooting, here are a couple of steps you could consider: • Double-check that your configuration exactly matches the expected format for the genericOAuth plugin. • As a temporary workaround, you might try manually appending the required parameters to the authorizationUrl if that’s feasible for your setup. • We’re actively investigating the issue to have a proper fix included in a future release. Does this workaround help your current setup, or do you have any additional details that might assist further? Tag @better-auth-agent if you would like an answer from the Agent. _If you need more help, tag @Skyvern 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

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

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

This is a known limitation in Better Auth's genericOAuth plugin. The authorizationUrlParams option is only processed statically at initialization, not dynamically per request, so function forms are never called and custom parameters like audience are not included in the authorization URL during the OAuth flow. This matches both the code and multiple issue reports from other users and maintainers (source).

Workarounds: You can append your custom parameters directly to the authorizationUrl string in your provider config (e.g., https://dev-xxx.us.auth0.com/authorize?audience=https://my-api/) (source). If you use discoveryUrl, you must override it and provide the authorizationUrl manually to include custom params. There is a pending PR to improve support for custom parameters, but as of v1.4.5, dynamic or function-based authorizationUrlParams are not supported.

If you need dynamic logic, the only current workaround is to create a custom API route that handles the OAuth redirect and injects parameters, but this adds complexity and is not officially supported (source).

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:3605269592 --> @dosubot[bot] commented on GitHub (Dec 3, 2025): <!-- Greeting --> Hi @hdisma! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known limitation in Better Auth's genericOAuth plugin. The authorizationUrlParams option is only processed statically at initialization, not dynamically per request, so function forms are never called and custom parameters like audience are not included in the authorization URL during the OAuth flow. This matches both the code and multiple issue reports from other users and maintainers ([source](https://github.com/better-auth/better-auth/issues/4453)). Workarounds: You can append your custom parameters directly to the authorizationUrl string in your provider config (e.g., https://dev-xxx.us.auth0.com/authorize?audience=https://my-api/) ([source](https://github.com/better-auth/better-auth/issues/1064)). If you use discoveryUrl, you must override it and provide the authorizationUrl manually to include custom params. There is a pending PR to improve support for custom parameters, but as of v1.4.5, dynamic or function-based authorizationUrlParams are not supported. If you need dynamic logic, the only current workaround is to create a custom API route that handles the OAuth redirect and injects parameters, but this adds complexity and is not officially supported ([source](https://github.com/better-auth/better-auth/issues/4453)). <!-- 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/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/776ff888-a4b7-4b99-aa09-1f6d5c739ed0?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=This%20is%20a%20known%20limitation%20in%20Better%20Auth%27s%20genericOAuth%20plugin.%20The%20authorizationUrlParams%20option%20is%20only%20processed%20statically%20at%20initialization%2C%20not%20dynamically%20per%20request%2C%20so%20function%20forms%20are%20never%20called%20and%20custom%20parameters%20like%20audience%20are%20not%20included%20in%20the%20authorization%20URL%20during%20the%20OAuth%20flow.%20This%20matches%20both%20the%20code%20and%20multiple%20issue%20reports%20from%20other%20users%20and%20maintainers%20%28%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/4453%29%29.%0A%0AWorkarounds%3A%20You%20can%20append%20your%20custom%20parameters%20directly%20to%20the%20authorizationUrl%20string%20in%20your%20provider%20config%20%28e.g.%2C%20https%3A//dev-xxx.us.auth0.com/authorize%3Faudience%3Dhttps%3A//my-api/%29%20%28%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/1064%29%29.%20If%20you%20use%20discoveryUrl%2C%20you%20must%20override%20it%20and%20provide%20the%20authorizationUrl%20manually%20to%20include%20custom%20params.%20There%20is%20a%20pending%20PR%20to%20improve%20support%20for%20custom%20parameters%2C%20but%20as%20of%20v1.4.5%2C%20dynamic%20or%20function-based%20authorizationUrlParams%20are%20not%20supported.%0A%0AIf%20you%20need%20dynamic%20logic%2C%20the%20only%20current%20workaround%20is%20to%20create%20a%20custom%20API%20route%20that%20handles%20the%20OAuth%20redirect%20and%20injects%20parameters%2C%20but%20this%20adds%20complexity%20and%20is%20not%20officially%20supported%20%28%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/4453%29%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/6486)
Author
Owner

@jslno commented on GitHub (Dec 4, 2025):

You should use authClient.signIn.oauth2 instead of signIn.social

<!-- gh-comment-id:3611194913 --> @jslno commented on GitHub (Dec 4, 2025): You should use `authClient.signIn.oauth2` instead of `signIn.social`
Author
Owner

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

Hi, @hdisma. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You reported that in Better Auth v1.4.5, the genericOAuth plugin does not invoke function forms of authorizationUrlParams, causing custom parameters like audience to be missing.
  • I confirmed this is a known limitation: authorizationUrlParams is processed statically at initialization only, so dynamic/function-based parameters are unsupported.
  • Workarounds include manually appending parameters to the authorizationUrl or using authClient.signIn.oauth2 instead of signIn.social.
  • A proper fix for this limitation is still under investigation.

Next Steps:

  • Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!

<!-- gh-comment-id:4006191094 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): Hi, @hdisma. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You reported that in Better Auth v1.4.5, the genericOAuth plugin does not invoke function forms of authorizationUrlParams, causing custom parameters like audience to be missing. - I confirmed this is a known limitation: authorizationUrlParams is processed statically at initialization only, so dynamic/function-based parameters are unsupported. - Workarounds include manually appending parameters to the authorizationUrl or using authClient.signIn.oauth2 instead of signIn.social. - A proper fix for this limitation is still under investigation. **Next Steps:** - Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thank you for your understanding and contribution!
Author
Owner

@reutersharry-sketch commented on GitHub (Mar 23, 2026):

Hi. Unfortunately, I still have this problem. On my side using the authorizationUrlParams either as a function or object blocks my genericOauth IDP from receiving userinfo. Are there any plans perhaps to revisit this issue? Thanks. Here is my setting for example:

 authorizationUrlParams: async (ctx) => {
            return {
              ...ctx.params,

              resource: process.env.AUTH_MY_RESOURCE,
            }
          },

Here is the setting for getUserInfo:

getUserInfo: async (tokens) => {
            console.log({ tokens })
            const accessToken = tokens?.accessToken
            const res = await fetch(`${process.env.AUTH_MY_AUTHORITY!}/userinfo`, {
              headers: { Authorization: `Bearer ${accessToken}` },
            })

            // if (!res.ok) return null

            const profile = await res.json()
            return {
              id: profile.sub,
              email: profile.email ?? null,
              name: profile.name ?? null,
              image: profile.picture ?? null,
              customerOrg: profile.customerOrg ?? null, // Map custom field
            }
          }

Result, I authenticated, and immediately I am kicked out from my IDP, then I get a 400 response which indicates that userinfo was not found. May aim is that when I share authorizationUrlParams with my IDP, it would consume the opaque access token I get from the user info, then return a fully-fledged access token.

<!-- gh-comment-id:4108813256 --> @reutersharry-sketch commented on GitHub (Mar 23, 2026): Hi. Unfortunately, I still have this problem. On my side using the authorizationUrlParams either as a function or object blocks my genericOauth IDP from receiving userinfo. Are there any plans perhaps to revisit this issue? Thanks. Here is my setting for example: ``` authorizationUrlParams: async (ctx) => { return { ...ctx.params, resource: process.env.AUTH_MY_RESOURCE, } }, ``` Here is the setting for getUserInfo: ``` getUserInfo: async (tokens) => { console.log({ tokens }) const accessToken = tokens?.accessToken const res = await fetch(`${process.env.AUTH_MY_AUTHORITY!}/userinfo`, { headers: { Authorization: `Bearer ${accessToken}` }, }) // if (!res.ok) return null const profile = await res.json() return { id: profile.sub, email: profile.email ?? null, name: profile.name ?? null, image: profile.picture ?? null, customerOrg: profile.customerOrg ?? null, // Map custom field } } ``` Result, I authenticated, and immediately I am kicked out from my IDP, then I get a 400 response which indicates that userinfo was not found. May aim is that when I share authorizationUrlParams with my IDP, it would consume the opaque access token I get from the user info, then return a fully-fledged access token.
Author
Owner

@github-actions[bot] commented on GitHub (Mar 31, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4165910933 --> @github-actions[bot] commented on GitHub (Mar 31, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19162