[GH-ISSUE #3926] SSO - OIDC - Google Invalid Scope #9764

Closed
opened 2026-04-13 05:27:45 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @bondandcoyne-craig on GitHub (Aug 11, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3926

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

When signing in via Google using Better Auth SSO (OIDC), Google returns 400 invalid_scope because the authorization request includes the offline_access scope. Google does not support the offline_access scope (it uses access_type=offline + prompt=consent to issue refresh tokens), so the request fails.

Environment

  • App framework: Next.js 15 (App Router)
  • Runtime: Node.js 22

Better Auth packages and versions:

  • "better-auth": "^1.3.4",
  • "@better-auth/sso": "^1.3.4",

OAuth provider

Google

Steps to Reproduce

Configure a Google provider in Better Auth SSO (OIDC).

Trigger sign-in:

const res = await auth.api.signInSSO({
  body: {
    providerId: 'google', // or your provider key
  },
})

Google responds with 400 and invalid_scope.

Hypothesis

Many OIDC providers (e.g., Azure AD) use the offline_access scope to request refresh tokens.

Google does not honor offline_access as a scope; adding it causes invalid_scope.

Better Auth appears to append offline_access when requesting offline/refresh capability, which breaks Google.

Current vs. Expected behavior

Current Behavior

Google rejects the request with:

Some requested scopes were invalid. {valid=[openid, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile], invalid=[offline_access]}
Error 400: invalid_scope

Expected Behavior

User is redirected to Google, consents, and returns to the app authenticated.

If refresh tokens are desired, Google should issue them when access_type=offline and prompt=consent are set on the authorization request, without requiring the offline_access scope.

What version of Better Auth are you using?

1.3.4

System info

System:
    OS: macOS 15.6
    CPU: (10) arm64 Apple M1 Pro
    Memory: 107.42 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
Browsers:
    Chrome: 139.0.7258.66
    Safari: 18.6

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

Package

Auth config (if applicable)

export const auth = betterAuth({
  baseURL: getEnv('NEXT_PUBLIC_BETTER_AUTH_BASE_URL'),
  trustedOrigins: [
    getEnv('NEXT_PUBLIC_BETTER_AUTH_BASE_URL') || 'http://app.localhost:3000',
  ],
  database: prismaAdapter(prisma, {
    provider: 'postgresql',
  }),
  plugins: [
    sso({
      organizationProvisioning: {
        disabled: false,
      },
    }),
    organization(),
  ],
})

Additional context

Hypothesis

Many OIDC providers (e.g., Azure AD) use the offline_access scope to request refresh tokens.

Google does not honor offline_access as a scope; adding it causes invalid_scope.

Better Auth appears to append offline_access when requesting offline/refresh capability, which breaks Google.

Originally created by @bondandcoyne-craig on GitHub (Aug 11, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3926 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce When signing in via Google using Better Auth SSO (OIDC), Google returns 400 invalid_scope because the authorization request includes the offline_access scope. Google does not support the offline_access scope (it uses access_type=offline + prompt=consent to issue refresh tokens), so the request fails. ### Environment - App framework: Next.js 15 (App Router) - Runtime: Node.js 22 #### Better Auth packages and versions: - "better-auth": "^1.3.4", - "@better-auth/sso": "^1.3.4", #### OAuth provider Google ### Steps to Reproduce Configure a Google provider in Better Auth SSO (OIDC). **Trigger sign-in:** ``` const res = await auth.api.signInSSO({ body: { providerId: 'google', // or your provider key }, }) ``` Google responds with 400 and invalid_scope. ### Hypothesis Many OIDC providers (e.g., Azure AD) use the offline_access scope to request refresh tokens. Google does not honor offline_access as a scope; adding it causes invalid_scope. Better Auth appears to append offline_access when requesting offline/refresh capability, which breaks Google. ### Current vs. Expected behavior ### Current Behavior Google rejects the request with: Some requested scopes were invalid. {valid=[openid, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile], invalid=[offline_access]} Error 400: invalid_scope ### Expected Behavior User is redirected to Google, consents, and returns to the app authenticated. If refresh tokens are desired, Google should issue them when access_type=offline and prompt=consent are set on the authorization request, without requiring the offline_access scope. ### What version of Better Auth are you using? 1.3.4 ### System info ```bash System: OS: macOS 15.6 CPU: (10) arm64 Apple M1 Pro Memory: 107.42 MB / 16.00 GB Shell: 5.9 - /bin/zsh Browsers: Chrome: 139.0.7258.66 Safari: 18.6 ``` ### Which area(s) are affected? (Select all that apply) Package ### Auth config (if applicable) ```typescript export const auth = betterAuth({ baseURL: getEnv('NEXT_PUBLIC_BETTER_AUTH_BASE_URL'), trustedOrigins: [ getEnv('NEXT_PUBLIC_BETTER_AUTH_BASE_URL') || 'http://app.localhost:3000', ], database: prismaAdapter(prisma, { provider: 'postgresql', }), plugins: [ sso({ organizationProvisioning: { disabled: false, }, }), organization(), ], }) ``` ### Additional context ### Hypothesis Many OIDC providers (e.g., Azure AD) use the offline_access scope to request refresh tokens. Google does not honor offline_access as a scope; adding it causes invalid_scope. Better Auth appears to append offline_access when requesting offline/refresh capability, which breaks Google.
GiteaMirror added the locked label 2026-04-13 05:27:45 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 11, 2025):

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

This is a known issue: Better Auth SSO appends the offline_access scope by default for all providers, including Google, which causes Google to return a 400 invalid_scope error because it doesn't support that scope. Google requires access_type=offline and prompt=consent instead, and does not use the offline_access scope for refresh tokens. There is currently no built-in way to configure Better Auth SSO to exclude offline_access just for Google or to automatically add Google's required parameters—this has been confirmed in both the code and multiple issues/discussions (example).

Workarounds are limited: explicitly setting the scopes in your sign-in request body (excluding offline_access) may not be respected due to how the SSO plugin handles defaults. Patching the code to add provider-specific logic for Google is the only reliable solution at the moment (code reference).

If you need refresh tokens from Google, you would need to ensure the authorization request omits offline_access and includes access_type: 'offline' and prompt: 'consent'. This is not currently possible without modifying the Better Auth code or waiting for an upstream fix (docs and config reference).

You can track related issues and PRs for updates:

If this is a blocker, a code patch to add provider-specific scope/parameter handling for Google is the recommended path.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3174274702 --> @dosubot[bot] commented on GitHub (Aug 11, 2025): <!-- Greeting --> Hi @bondandcoyne-craig! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known issue: Better Auth SSO appends the `offline_access` scope by default for all providers, including Google, which causes Google to return a 400 `invalid_scope` error because it doesn't support that scope. Google requires `access_type=offline` and `prompt=consent` instead, and does not use the `offline_access` scope for refresh tokens. There is currently no built-in way to configure Better Auth SSO to exclude `offline_access` just for Google or to automatically add Google's required parameters—this has been confirmed in both the code and multiple issues/discussions ([example](https://github.com/better-auth/better-auth/issues/2360)). Workarounds are limited: explicitly setting the scopes in your sign-in request body (excluding `offline_access`) may not be respected due to how the SSO plugin handles defaults. Patching the code to add provider-specific logic for Google is the only reliable solution at the moment ([code reference](https://github.com/better-auth/better-auth/blob/f281c92b9940fe6e81e05c07d24b73f2c2f8bfdd/packages/better-auth/src/plugins/sso/index.ts)). If you need refresh tokens from Google, you would need to ensure the authorization request omits `offline_access` and includes `access_type: 'offline'` and `prompt: 'consent'`. This is not currently possible without modifying the Better Auth code or waiting for an upstream fix ([docs and config reference](https://better-auth.com/docs/plugins/generic-oauth)). You can track related issues and PRs for updates: - [Issue: offline_access scope causes invalid_scope with Google](https://github.com/better-auth/better-auth/issues/2360) - [Recent PRs improving OIDC/refresh token support (not Google-specific)](https://github.com/better-auth/better-auth/pull/3373) If this is a blocker, a code patch to add provider-specific scope/parameter handling for Google is the recommended path. <!-- 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/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/63b407c8-6fa2-49c1-a496-c89baa374e15?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&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/3926)
Author
Owner

@himself65 commented on GitHub (Aug 11, 2025):

You can customize the scopes by setting the options.scopes to other values in SSO plugin. The default is ["openid", "email", "profile", "offline_access",]

<!-- gh-comment-id:3174433938 --> @himself65 commented on GitHub (Aug 11, 2025): You can customize the `scopes` by setting the `options.scopes` to other values in SSO plugin. The default is `["openid", "email", "profile", "offline_access",]`
Author
Owner

@frectonz commented on GitHub (Aug 11, 2025):

For more updates look at #2360

<!-- gh-comment-id:3175696370 --> @frectonz commented on GitHub (Aug 11, 2025): For more updates look at #2360
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9764