Skip to content

fix(generic-oauth): support symmetric ID token verification - #11237

Open
jhapriyavart10 wants to merge 3 commits into
better-auth:mainfrom
jhapriyavart10:fix/generic-oauth-hs256-id-token
Open

fix(generic-oauth): support symmetric ID token verification#11237
jhapriyavart10 wants to merge 3 commits into
better-auth:mainfrom
jhapriyavart10:fix/generic-oauth-hs256-id-token

Conversation

@jhapriyavart10

@jhapriyavart10 jhapriyavart10 commented Sep 10, 2026

Copy link
Copy Markdown

Summary

When configuring an OIDC provider with discoveryUrl, genericOAuth currently binds ID-token verification strictly to createRemoteJWKSet(jwksUrl). For identity providers that issue symmetrically signed ID tokens (e.g. HS256, HS384, HS512), verification unconditionally fails with JWKSNoMatchingKey because OIDC Discovery §3 specifies that symmetric keys must not be published in the public JWKS.

Root Cause

genericOAuth's discovery initialization unconditionally assigns idTokenConfig.jwks = createRemoteJWKSet(jwksUrl) whenever discovered.jwks_uri and discovered.issuer are present, without inspecting the token's algorithm header at verification time.

Fix

  • Wrap remoteJWKS in an algorithm-aware JWTVerifyGetKey resolver.
  • For exact HMAC algorithms (HS256, HS384, HS512), verify using the pre-encoded bytes of the configured clientSecret per OIDC Core 1.0 §3.1.3.7.
  • For asymmetric algorithms, continue delegating directly to remoteJWKS.
  • Preserve all existing issuer, audience, nonce, and algorithm restriction checks.
  • If clientSecret is absent or empty, HMAC verification safely fails closed.

Tests

Added regression tests under describe("HS256 discovery verification") in packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts:

  • Validates authentic HS256 ID-token verification across both OAuth redirect flow (with nonce binding) and direct client sign-in.
  • Validates rejection when signed with an incorrect secret.
  • Validates algorithm enforcement (rejecting HS256 tokens when discovery specifies only RS256).
  • Full generic-oauth suite passes (130/130).
  • pnpm typecheck passes with 0 errors.

Closes #11121


Summary by cubic

Fixes generic OAuth ID token verification for providers that issue symmetric (HS256/HS384/HS512) tokens. Verification previously always used the remote JWKS, which per OIDC Discovery doesn't include symmetric keys, so these tokens failed with JWKSNoMatchingKey. Now HMAC tokens are verified against the pre-encoded clientSecret, but only when the token's algorithm is advertised in the discovery metadata; asymmetric tokens keep using the JWKS, and verification fails closed if clientSecret is missing or the algorithm isn't advertised.

Tests

  • Added regression tests for valid HS256 tokens, invalid-secret rejection, missing/empty-secret rejection, and enforced algorithm restrictions from discovery, including confirmation that JWKS isn't requested when verification fails closed.

Written for commit be89cec. Summary will update on new commits.

Review in cubic

@jhapriyavart10
jhapriyavart10 requested a review from a team as a code owner September 10, 2026 05:48
Copilot AI lite review requested due to automatic review settings September 10, 2026 05:48
@jhapriyavart10
jhapriyavart10 requested a review from a team as a code owner September 10, 2026 05:48
@jhapriyavart10
jhapriyavart10 requested review from gustavovalverde and removed request for a team September 10, 2026 05:48
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

@jhapriyavart10 is attempting to deploy a commit to the better-auth Team on Vercel.

A member of the Team first needs to authorize it.

@better-release better-release Bot added the oauth Social providers, OAuth flows, generic-oauth, oauth-proxy label Sep 10, 2026
@greptile-apps

greptile-apps Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds algorithm-aware generic OAuth ID-token verification, using the configured client secret only for explicitly advertised HMAC algorithms while retaining remote JWKS verification for asymmetric tokens.

  • Supports HS256, HS384, and HS512 ID tokens from discovery-based providers.
  • Fails closed when the HMAC algorithm is not advertised or the client secret is missing or empty.
  • Adds coverage for redirect and direct sign-in flows, invalid secrets, algorithm restrictions, and missing configuration.
  • The changes since the previous review add assertions confirming rejected HMAC tokens do not fall back to the public JWKS endpoint.

Confidence Score: 5/5

The PR appears safe to merge, with the previous algorithm-advertisement issue resolved and no new actionable failures identified.

HMAC verification now requires an exact algorithm advertised by discovery metadata and a non-empty configured client secret; otherwise it rejects before accessing the remote JWKS. The previous finding was manually resolved, and the current implementation and tests address its fail-closed requirement.

Reviews (3): Last reviewed commit: "test(generic-oauth): verify HMAC fail-cl..." | Re-trigger Greptile

Comment thread packages/better-auth/src/plugins/generic-oauth/index.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The HS* key resolver currently falls back to remote JWKS when clientSecret is missing/empty, which can violate the “fail closed” expectation and may weaken verification for misconfigured providers.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates the generic-oauth plugin’s OIDC discovery-based ID token verification so that symmetric ID tokens (HS256/HS384/HS512) can be verified using the configured clientSecret, while asymmetric algorithms continue to use the remote JWKS from discovery metadata—addressing failures like JWKSNoMatchingKey for providers that correctly omit symmetric keys from public JWKS.

Changes:

  • Wraps the discovery JWKS resolver with an alg-aware key resolver that returns clientSecret bytes for HS* algorithms.
  • Adds regression tests covering HS256 verification for both redirect flow (nonce-bound) and direct client idToken sign-in, plus negative cases.
  • Adds a changeset documenting the patch behavior change for better-auth.
File summaries
File Description
packages/better-auth/src/plugins/generic-oauth/index.ts Makes ID-token key resolution algorithm-aware, using clientSecret for HS* and remote JWKS for asymmetric algorithms.
packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts Adds HS256 discovery verification regression tests (happy path + rejection cases).
.changeset/generic-oauth-hs256-id-token.md Publishes a patch changeset describing the new HS* discovery verification behavior.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +249 to +260
jwks: async (protectedHeader, token) => {
if (
protectedHeader.alg === "HS256" ||
protectedHeader.alg === "HS384" ||
protectedHeader.alg === "HS512"
) {
if (secretBytes) {
return secretBytes;
}
}
return remoteJWKS(protectedHeader, token);
},

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread packages/better-auth/src/plugins/generic-oauth/index.ts Outdated
Comment thread packages/better-auth/src/plugins/generic-oauth/index.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

oauth Social providers, OAuth flows, generic-oauth, oauth-proxy

Projects

None yet

Development

Successfully merging this pull request may close these issues.

genericOAuth cannot verify HS256 id_tokens: JWKS resolver is chosen from jwks_uri presence rather than the token's alg

2 participants