[PR #9058] [MERGED] fix(sso): include RelayState in signed SAML AuthnRequests #25307

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

📋 Pull Request Information

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

Base: mainHead: fix/saml-relay-state-signing


📝 Commits (2)

  • 71307da fix(sso): include RelayState in signed SAML AuthnRequests
  • 3f11df9 fix(sso): add missing spMetadata to satisfy SAMLConfig type

📊 Changes

3 files changed (+226 additions, -54 deletions)

View changed files

.changeset/saml-relay-state-signing.md (+8 -0)
📝 packages/sso/src/routes/sso.ts (+12 -11)
📝 packages/sso/src/saml.test.ts (+206 -43)

📄 Description

RelayState was appended after the AuthnRequest signature was computed, so it was not covered by the signed octet string per SAML 2.0 Bindings §3.4.4.1. Spec-compliant IdPs rejected these requests.

  • Move generateRelayState() before SP construction and pass the token via relayState so samlify includes it in the signature
  • Make authnRequestsSigned: true without a private key a hard error instead of a silent warning
  • Add signature-verifying mock IdP to tests (port 8082) that rejects invalid signatures
  • Document that a private key is required when signing is enabled

Closes #6048 — superseded by this PR, which applies the fix on current main architecture.


Summary by cubic

Fixes signed SAML AuthnRequests so RelayState is included in the HTTP-Redirect signature, making requests compliant with SAML 2.0 Bindings §3.4.4.1 and accepted by strict IdPs.

  • Bug Fixes

    • Generate RelayState before SP construction and pass it as relayState to samlify so it’s included in the signed octet string.
    • Throw when authnRequestsSigned: true is set without an SP private key (no more silent unsigned requests).
    • Use samlify’s signed redirect URL (no manual &RelayState=...).
    • Tests: add a signature-verifying mock IdP (port 8082) for HTTP-Redirect; assert RelayState precedes Signature and verify SigAlg; add missing spMetadata in the no-key test to satisfy SAMLConfig typing.
  • Migration

    • If authnRequestsSigned is enabled, set a private key in samlConfig.spMetadata.privateKey or samlConfig.privateKey; otherwise sign-in will fail.

Written for commit 3f11df95ad. 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/9058 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 4/9/2026 **Status:** ✅ Merged **Merged:** 4/9/2026 **Merged by:** [@gustavovalverde](https://github.com/gustavovalverde) **Base:** `main` ← **Head:** `fix/saml-relay-state-signing` --- ### 📝 Commits (2) - [`71307da`](https://github.com/better-auth/better-auth/commit/71307da743d28d9e2d9c1d602d775fa8e5537024) fix(sso): include RelayState in signed SAML AuthnRequests - [`3f11df9`](https://github.com/better-auth/better-auth/commit/3f11df95adb2715c6d9af622ae649e9909a4889b) fix(sso): add missing spMetadata to satisfy SAMLConfig type ### 📊 Changes **3 files changed** (+226 additions, -54 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/saml-relay-state-signing.md` (+8 -0) 📝 `packages/sso/src/routes/sso.ts` (+12 -11) 📝 `packages/sso/src/saml.test.ts` (+206 -43) </details> ### 📄 Description RelayState was appended after the AuthnRequest signature was computed, so it was not covered by the signed octet string per SAML 2.0 Bindings §3.4.4.1. Spec-compliant IdPs rejected these requests. - Move `generateRelayState()` before SP construction and pass the token via `relayState` so samlify includes it in the signature - Make `authnRequestsSigned: true` without a private key a hard error instead of a silent warning - Add signature-verifying mock IdP to tests (port 8082) that rejects invalid signatures - Document that a private key is required when signing is enabled Closes #6048 — superseded by this PR, which applies the fix on current `main` architecture. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes signed SAML AuthnRequests so RelayState is included in the HTTP-Redirect signature, making requests compliant with SAML 2.0 Bindings §3.4.4.1 and accepted by strict IdPs. - **Bug Fixes** - Generate RelayState before SP construction and pass it as `relayState` to `samlify` so it’s included in the signed octet string. - Throw when `authnRequestsSigned: true` is set without an SP private key (no more silent unsigned requests). - Use `samlify`’s signed redirect URL (no manual `&RelayState=...`). - Tests: add a signature-verifying mock IdP (port 8082) for HTTP-Redirect; assert `RelayState` precedes `Signature` and verify `SigAlg`; add missing `spMetadata` in the no-key test to satisfy `SAMLConfig` typing. - **Migration** - If `authnRequestsSigned` is enabled, set a private key in `samlConfig.spMetadata.privateKey` or `samlConfig.privateKey`; otherwise sign-in will fail. <sup>Written for commit 3f11df95adb2715c6d9af622ae649e9909a4889b. 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:49:24 -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#25307