[PR #9079] [MERGED] feat(oauth-provider): compute at_hash in id tokens per OIDC Core §3.1.3.6 #25322

Closed
opened 2026-04-15 22:50:03 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/9079
Author: @gustavovalverde
Created: 4/9/2026
Status: Merged
Merged: 4/11/2026
Merged by: @gustavovalverde

Base: nextHead: feat/oauth-provider-at-hash-v2


📝 Commits (4)

  • b55570e feat(oauth-provider): compute at_hash in id tokens per OIDC Core §3.1.3.6
  • 4320fa8 chore: add changeset for at_hash feature
  • b29f79e fix(oauth-provider): omit at_hash when custom signer alg is unknown
  • 2491027 refactor(oauth-provider): resolve signing key once, add runtime alg validation

📊 Changes

6 files changed (+387 additions, -45 deletions)

View changed files

.changeset/oauth-provider-at-hash.md (+10 -0)
📝 packages/better-auth/src/plugins/jwt/index.ts (+1 -1)
📝 packages/better-auth/src/plugins/jwt/sign.ts (+46 -22)
📝 packages/better-auth/src/plugins/jwt/types.ts (+13 -0)
📝 packages/oauth-provider/src/token.test.ts (+236 -3)
📝 packages/oauth-provider/src/token.ts (+81 -19)

📄 Description

Summary

OIDC Core §3.1.3.6 requires the at_hash claim in ID tokens when issued alongside an access token. This binds the two tokens cryptographically, preventing token substitution attacks.

  • Adds computeOidcHash() that selects the correct hash algorithm based on the signing algorithm (EdDSA to SHA-512, *384 to SHA-384, *512 to SHA-512, else SHA-256)
  • Derives the algorithm from the actual stored JWKS key via new resolveSigningAlgorithm(), not from config (avoids mismatch during key rotation)
  • Sequences ID token creation after access token so the hash can be computed
  • The raw access token is never exposed to customIdTokenClaims callbacks

Supersedes #8634 (rebased cleanly on current main, preserving all existing test suites and timestamp utilities).

References


Summary by cubic

Adds the at_hash claim to ID tokens issued with access tokens, computing it with the actual signing key’s algorithm per OIDC. Resolves the signing key once for signing and validation to prevent algorithm mismatches.

  • New Features

    • Compute at_hash with the real signing algorithm; create the ID token after the access token; omit at_hash if a custom signer’s alg is unknown.
    • Keep the raw access token out of customIdTokenClaims.
  • Refactors

    • Export resolveSigningKey() from better-auth/plugins/jwt (re-exported via better-auth/plugins) and pass it to signJWT via resolvedKey to avoid redundant lookups and rotation races.
    • When using a custom jwt.sign, validate the ID token header’s alg against the declared algorithm.

Written for commit 2491027e6d. Summary will update on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/9079 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 4/9/2026 **Status:** ✅ Merged **Merged:** 4/11/2026 **Merged by:** [@gustavovalverde](https://github.com/gustavovalverde) **Base:** `next` ← **Head:** `feat/oauth-provider-at-hash-v2` --- ### 📝 Commits (4) - [`b55570e`](https://github.com/better-auth/better-auth/commit/b55570e931dcd1a9f4d3b6c2d72b3ec1362fd6a4) feat(oauth-provider): compute at_hash in id tokens per OIDC Core §3.1.3.6 - [`4320fa8`](https://github.com/better-auth/better-auth/commit/4320fa809f096844a287b01efa2e0b55bec1494b) chore: add changeset for at_hash feature - [`b29f79e`](https://github.com/better-auth/better-auth/commit/b29f79e58d47f0198dd143dc54eefb5d7d605aa7) fix(oauth-provider): omit at_hash when custom signer alg is unknown - [`2491027`](https://github.com/better-auth/better-auth/commit/2491027e6d78aa4121a88185636af761cdf08b96) refactor(oauth-provider): resolve signing key once, add runtime alg validation ### 📊 Changes **6 files changed** (+387 additions, -45 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/oauth-provider-at-hash.md` (+10 -0) 📝 `packages/better-auth/src/plugins/jwt/index.ts` (+1 -1) 📝 `packages/better-auth/src/plugins/jwt/sign.ts` (+46 -22) 📝 `packages/better-auth/src/plugins/jwt/types.ts` (+13 -0) 📝 `packages/oauth-provider/src/token.test.ts` (+236 -3) 📝 `packages/oauth-provider/src/token.ts` (+81 -19) </details> ### 📄 Description ## Summary OIDC Core §3.1.3.6 requires the `at_hash` claim in ID tokens when issued alongside an access token. This binds the two tokens cryptographically, preventing token substitution attacks. - Adds `computeOidcHash()` that selects the correct hash algorithm based on the signing algorithm (EdDSA to SHA-512, *384 to SHA-384, *512 to SHA-512, else SHA-256) - Derives the algorithm from the actual stored JWKS key via new `resolveSigningAlgorithm()`, not from config (avoids mismatch during key rotation) - Sequences ID token creation after access token so the hash can be computed - The raw access token is never exposed to `customIdTokenClaims` callbacks Supersedes #8634 (rebased cleanly on current main, preserving all existing test suites and timestamp utilities). ## References - [OIDC Core §3.1.3.6](https://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken) <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds the `at_hash` claim to ID tokens issued with access tokens, computing it with the actual signing key’s algorithm per OIDC. Resolves the signing key once for signing and validation to prevent algorithm mismatches. - **New Features** - Compute `at_hash` with the real signing algorithm; create the ID token after the access token; omit `at_hash` if a custom signer’s alg is unknown. - Keep the raw access token out of `customIdTokenClaims`. - **Refactors** - Export `resolveSigningKey()` from `better-auth/plugins/jwt` (re-exported via `better-auth/plugins`) and pass it to `signJWT` via `resolvedKey` to avoid redundant lookups and rotation races. - When using a custom `jwt.sign`, validate the ID token header’s `alg` against the declared algorithm. <sup>Written for commit 2491027e6d78aa4121a88185636af761cdf08b96. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 22:50:03 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#25322