Tags: zitadel/oidc
Tags
feat(oidc): add client_id_metadata_document_supported discovery metad… …ata (#905) # Which Problems Are Solved A provider built on this library cannot advertise support for the OAuth Client ID Metadata Document (CIMD) spec in its discovery document, because `DiscoveryConfiguration` has no field for the standard `client_id_metadata_document_supported` Authorization Server Metadata property. # How the Problems Are Solved - Add an additive boolean field `ClientIDMetadataDocumentSupported` to `DiscoveryConfiguration` in `pkg/oidc/discovery.go`, serialized as `client_id_metadata_document_supported` with `omitempty`. - Extend `TestDiscover` to cover JSON serialization of the new field. # Additional Changes - None. No change to the `op.Server` interface, no handler, no CIMD resolution logic. The flag defaults to false and is omitted from existing discovery output via `omitempty`, so there is no behavior change for current providers. # Additional Context - Spec: draft-ietf-oauth-client-id-metadata-document (OAuth WG), Section 5, field `client_id_metadata_document_supported`: https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/ - Context: RFC 8414 (Authorization Server Metadata), OpenID Connect Discovery 1.0. - Use case: MCP client identification, SEP-991: modelcontextprotocol/modelcontextprotocol#991 - Closes #904 - Complementary to #782 (dynamic client registration); additive, no interface change. --------- Co-authored-by: Livio Spring <9405495+livio-a@users.noreply.github.com>
fix(op): update stale v3 import in token_request_test.go (#920) # Which Problems Are Solved - `pkg/op/token_request_test.go` imported `github.com/zitadel/oidc/v3/...` while the module itself is `github.com/zitadel/oidc/v4`, causing the test file to reference a different major version than the rest of the codebase. # How the Problems Are Solved - Updated the two imports (`pkg/oidc` and `pkg/op`) in `pkg/op/token_request_test.go` from `v3` to `v4`. # Additional Changes None. # Additional Context None. --- _Generated by [Claude Code](https://claude.ai/code/session_01EbHcRepm3aWad8tsRE3ZhT)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
fix: only allow one authenticate method (#858) according to the RFC 6749 §2.3 `The client MUST NOT use more than one authentication method in each request.` this PR resolve issue #857 1. add the logic to only have one authenticate method in client side 2. add the restrict on the OP side to only allow one authenticate method. 3. deprecated interface `ClientSecretBasicAuthRequest` and the Auth() function 4. add interface `AuthenticatedTokenRequestAuthMethodChecker` and added the only one auth method check for input tokens that implemented such checker interface. NOTE: the Auth() function is no longer invoked after this PR, but we keep the public API. test: added united test ### Definition of Ready - [x] I am happy with the code - [x] Short description of the feature/issue is added in the pr description ~~- [ ] PR is linked to the corresponding user story~~ - [ ] Acceptance criteria are met ~~- [ ] All open todos and follow ups are defined in a new ticket and justified~~ ~~- [ ] Deviations from the acceptance criteria and design are agreed with the PO and documented.~~ - [x] No debug or dead code - [x] My code has no repetitions - [x] Critical parts are tested automatically ~~- [ ] Where possible E2E tests are implemented~~ ~~- [ ] Documentation/examples are up-to-date~~ - [ ] All non-functional requirements are met ~~- [ ] Functionality of the acceptance criteria is checked manually on the dev system.~~ --------- Co-authored-by: Wim Van Laer <wim@wvl.app> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
fix(op): add client ownership check to LegacyServer CodeExchange (#902) LegacyServer.CodeExchange looks up the auth request by code only, without checking that the authenticated client owns it. The modern path in ValidateAccessTokenRequest (token_code.go:59) checks: if client.GetID() != authReq.GetClientID() { return error } This adds the same check to LegacyServer.CodeExchange. --------- Co-authored-by: Wim Van Laer <wim@wvl.app>
fix(op): add client ownership check to LegacyServer CodeExchange (#902) LegacyServer.CodeExchange looks up the auth request by code only, without checking that the authenticated client owns it. The modern path in ValidateAccessTokenRequest (token_code.go:59) checks: if client.GetID() != authReq.GetClientID() { return error } This adds the same check to LegacyServer.CodeExchange. --------- Co-authored-by: Wim Van Laer <wim@wvl.app>
fix(op): resolve client before RedirectToLogin for custom AuthorizeVa… …lidator (#910) ### Definition of Ready - [x] I am happy with the code - [x] Short description of the feature/issue is added in the PR description - [x] PR is linked to the corresponding user story ## Which Problems Are Solved Fixes #909. `op.Authorize` panics with a nil-pointer dereference in `RedirectToLogin` when the `Authorizer` implements the `op.AuthorizeValidator` interface. `Authorize` populates its local `client` only inside the *default* validation closure; supplying a custom `AuthorizeValidator` replaces that closure, so `client` stays `nil` and `RedirectToLogin` (`client.LoginURL`) panics for any well-formed auth request. ## How the Problems Are Solved Before the login redirect, if `client` is still `nil` (a custom validator was used and did not assign it), resolve it via `Storage().GetClientByClientID`, mapping a lookup error to the standard `AuthRequestError` path. ## Additional Context - The `AuthorizeValidator` interface is documented as the seam to customize validation, but using it currently crashes the standard login-redirect path. - The change passes the existing `pkg/op` test suite unchanged. - Happy to add a regression test in your preferred style — the path needs an `Authorizer` that also implements `AuthorizeValidator`, and `op.AuthRequest` has no mock today, so I wanted to confirm the approach/test conventions with you first. --------- Signed-off-by: abuobaida <mho1910@gmail.com> Co-authored-by: abuobaida <mho1910@gmail.com> Co-authored-by: zaki <zaki@hermes.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Wim Van Laer <wim@wvl.app>
fix: made bearer token scheme case-insensitive for non-spec-compliant… … oidc providers (#877) # Which Problems Are Solved When a client requested userinfo with a lowercase authorization header (`bearer` instead of `Bearer`), the server would reject it because it is not compliant to the spec. # How the Problems Are Solved - made the bearer scheme check case-insensitive # Additional Changes # Additional Context - Closes #876
fix(op): allow dynamic loopback ports in post_logout_redirect_uri per… … RFC 8252 §7.3 (#875) # Which Problems Are Solved - The end-session endpoint rejects valid `post_logout_redirect_uri` values from native (desktop) apps that use the loopback interface with a dynamic port. Registering `http://127.0.0.1/callback` and logging out via `http://127.0.0.1:54321/callback` returns `{"error":"invalid_request","error_description":"post_logout_redirect_uri invalid"}`, even though the same client can authenticate via that exact loopback URI without issue. - This breaks RP-initiated logout for any native app that follows [RFC 8252 §7.3](https://datatracker.ietf.org/doc/html/rfc8252#section-7.3) ("Loopback Interface Redirection"), which states that the authorization server *MUST* allow any port to be specified at request time for loopback IP redirect URIs. - The asymmetry exists because the auth-request side already implements RFC 8252 §7.3 for `redirect_uri` (see `validateAuthReqRedirectURINative`), but `ValidateEndSessionPostLogoutRedirectURI` was a plain string-equality check. # How the Problems Are Solved - `ValidateEndSessionPostLogoutRedirectURI` in `pkg/op/session.go` gains a native-app loopback branch placed between the existing exact-match loop and the existing `HasRedirectGlobs` (DevMode) branch. - The new branch reuses the helpers already used by the auth-request validator: `HTTPLoopbackOrLocalhost` (parses an http/https URI and reports whether the host is `127.0.0.1`, `[::1]`, or `localhost`) and `equalURI` (compares only path + raw query). When the client is `ApplicationTypeNative` and the incoming `post_logout_redirect_uri` resolves to a loopback host, each registered URI is parsed the same way and compared without considering the port — matching the auth-side semantics exactly. - No change to public API. No change to the Client/HasRedirectGlobs interfaces. # Additional Changes - Adds `pkg/op/session_test.go` with table-driven coverage for `ValidateEndSessionPostLogoutRedirectURI`. The table covers: existing exact / no-match / glob cases (regression guard), native loopback v4/v6/localhost dynamic ports, native HTTPS loopback, native cross-loopback equivalence (v4 ↔ v6, inherited from `equalURI`), wrong-path negatives, web/user-agent dynamic-port rejection, and the literal RFC 8252 §7.3 example URIs (`http://127.0.0.1:51004/oauth2redirect/example-provider`, `http://[::1]:61023/oauth2redirect/example-provider`) plus the §8.3 `localhost` variant. Total: 24 cases, all passing. # Additional Context - Closes zitadel/zitadel#6615 (filed 2023-09-25). - Mirrors the existing native-app handling in `pkg/op/auth_request.go` (`validateAuthReqRedirectURINative`, lines 352-382 in v3.47.0) so that auth and logout treat loopback URIs consistently.
fix: URL-encode client credentials in Basic Auth per RFC 6749 §2.3.1 (#… …873) ## Summary Four `Auth()` methods call `req.SetBasicAuth()` with raw client credentials. Per [RFC 6749 Section 2.3.1](https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1), client credentials MUST be encoded using the `application/x-www-form-urlencoded` encoding algorithm before being sent via HTTP Basic Authentication. `net/http.SetBasicAuth` only base64-encodes the credentials — it does not URL-encode them first. When a client secret contains characters like `%`, authorization servers that URL-decode per the RFC (e.g., Keycloak) fail with errors like `URLDecoder: Incomplete trailing escape (%) pattern`. The existing `AuthorizeBasic()` helper in `pkg/http/http.go` already correctly applies `url.QueryEscape`. This PR applies the same encoding to the four `Auth()` methods that were missing it: - `RefreshTokenRequest.Auth` (`pkg/client/rp/relying_party.go`) - `RevokeRequest.Auth` (`pkg/client/client.go`) - `DeviceAccessTokenRequest.Auth` (`pkg/client/client.go`) - `ClientCredentialsRequest.Auth` (`pkg/oidc/token_request.go`) ## Related This is distinct from #857 / #858 (duplicate credentials issue), though both stem from the same `Auth()` methods. This PR fixes the encoding bug without removing the `ClientSecretBasicAuthRequest` interface, so it is not a breaking change. ## Testing All existing tests pass. The fix is a one-line change per method, consistent with the pattern already used by `AuthorizeBasic()`.
fix: propagate signature verification errors correctly (#872) # Which Problems Are Solved The error returned after the signature verification fails is not propagated correctly to the calling function. # How the Problems Are Solved The error is wrapped (using the %w verb) instead of embedding (with the %v verb) the error message before returning to the caller. # Additional Changes Update test cases to assert the error type. # Additional Context - Closes #864
PreviousNext