Skip to content

Tags: zitadel/oidc

Tags

v3.49.2

Toggle v3.49.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: tracing key, doc rephrasing and guard slog.SetDefault against nil (

#935)

- pkg/client/rp/relying_party.go:881 — EndSession tracing span was named
"RefreshTokens"; now "EndSession".
- pkg/op/token_request.go:89 — rewrote the
AuthenticatedTokenRequestAuthMethodChecker doc comment to say what it
does, that ParseAuthenticatedTokenRequest uses it to enforce RFC 6749
§2.3, and that requests not implementing it are skipped.
- example/server/exampleop/op.go:38 — slog.SetDefault(logger) now
guarded against a nil logger, with a note that replacing the
process-wide logger is example-only behaviour.

<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/oidc/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
-->

# Which Problems Are Solved

- pkg/client/rp/relying_party.go:881 — EndSession tracing span was named
"RefreshTokens"; now "EndSession".
- pkg/op/token_request.go:89 — rewrote the
AuthenticatedTokenRequestAuthMethodChecker doc comment to say what it
does, that ParseAuthenticatedTokenRequest uses it to enforce RFC 6749
§2.3, and that requests not implementing it are skipped.
- example/server/exampleop/op.go:38 — slog.SetDefault(logger) now
guarded against a nil logger, with a note that replacing the
process-wide logger is example-only behaviour.

# How the Problems Are Solved

# Additional Changes

# Additional Context

v3.49.1

Toggle v3.49.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(op): reject requested_token_type that cannot be issued (#932)

# Which Problems Are Solved

A token exchange asking for
`requested_token_type=urn:ietf:params:oauth:token-type:jwt` returns
`200` with an empty token:


{"access_token":"","issued_token_type":"urn:ietf:params:oauth:token-type:jwt","token_type":"","scope":"openid
offline_access"}

`ValidateTokenExchangeRequest` accepts the type, since
`TokenType.IsSupported` covers all of `AllTokenTypes`.
`CreateTokenExchangeResponse` has no case for it, and its `default:`
branch builds the error but never returns it, so `token` and `tokenType`
stay empty and are marshalled as a success. RFC 8693 §2.2.1 makes
`access_token` and `token_type` REQUIRED in a successful response; a
client that checks the status code takes the empty string as its token.

# How the Problems Are Solved

Returns the error that branch already constructs, matching the other
error paths in the function. The response becomes `400
{"error":"invalid_request","error_description":"requested_token_type is
invalid"}`. Behaviour is unchanged for `access_token`, `refresh_token`
and `id_token`.

# Additional Changes

Adds a `TestRoutes` case for the jwt requested token type. I verified it
fails without the one-line change (`expected: 400, actual: 200`) and
passes with it.

# Additional Context

Compatibility: an omitted or empty `requested_token_type` reaches the
same `default:` branch, so a `TokenExchangeStorage` that does not
default it in `ValidateTokenExchangeRequest` — `pkg/op/storage.go:90`
recommends it, nothing enforces it — moves from that same empty `200` to
a `400`. Happy to default that case instead of rejecting it, if you
would prefer.

`go vet ./...` is clean; `go test -race ./pkg/...` passes apart from the
pre-existing `"expires_in":299` assertions, which flake on darwin/arm64
here for reasons unrelated to this change.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Wim Van Laer <wim@wvl.app>

v3.49.0

Toggle v3.49.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: support custom issuer verifier (#928)

<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/oidc/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
-->

# Which Problems Are Solved
Azure split issuer by tenent id
`https://login.microsoftonline.com/{tenantid}/v2.0`
when we want support more general users, like both company and personal
users, the issuer is dynamically different by the tenent. the discovery
endpoint
[https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration](https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration)
shows the `{tenantid}` pattern as well.

This PR support customized issuer verifier to support dynamic issuer. 

reference: 

https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri

# How the Problems Are Solved

This PR support customized issuer verifier to support dynamic issuer. 

# Additional Changes

change all the usage to use the new function
`oidc.CheckIssuerWithISSVerifier(claims, v.Issuer, v.ISS)`
it does not change current or default usage, just add option to support
cusomized issuer verifier.

# Additional Context

v4.0.0-next.4

Toggle v4.0.0-next.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(oidc): callTokenEndpoint expiry conversion error (#929)

<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/oidc/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
-->

# Which Problems Are Solved

A bug was introduced in the PR #821
which changes `exp` claim in `AccessTokenResponse` from a `int64` to an
`oidc.Duration` but does not update `callTokenEndpoint`. Thus,
`callTokenEndpoint` still treats it as int64 and and multiples it by
`time.second`. This results in an incorrect Expiry value, depending on
the `expiresIn` value it can be ahead by 30 years all the way to dates
well exceeding the time period of Futurama.

# How the Problems Are Solved

We fix this bug by updating `callTokenEndpoint` to bring in line the
intent of #821

From: `Expiry: time.Now().UTC().Add(time.Duration(tokenRes.ExpiresIn) *
time.Second),`
To: `Expiry: time.Now().UTC().Add(tokenRes.ExpiresIn.AsDuration()),`

# Additional Changes

We also add a simple regression test for this bug.

# Additional Context

Note this that only impacts v4 and v3 since this change from `int64` to
`oidc.Duration` only exists in v4. We encountered this bug when
preparing OpenPubkey connect to update from v3 to v4
openpubkey/openpubkey#392

v3.48.1

Toggle v3.48.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(rp): use redirect host for CLI callback server (#926)

# Which Problems Are Solved

- The CLI authorization flow always opens
`http://localhost:<port>/login`, regardless of the loopback host
configured in the redirect URI.
- The callback server always listens on `:<port>`, ignoring an explicit
IPv4 or IPv6 loopback address in the redirect URI.
- Consequently, callers cannot ensure that the callback server and
browser use the same explicit loopback address.
- Invalid or inconsistent callback configurations are not detected
before the server starts.

# How the Problems Are Solved

- Derives both the callback listener address and the browser `/login`
URL from the configured redirect URI.
- Binds directly to explicit IPv4 and IPv6 loopback addresses, ensuring
that the browser and callback server use the same address family.
- Validates that the redirect URI:
    - uses HTTP
    - contains an explicit port matching the CLI port
    - uses `localhost` or a loopback IP address
    - contains the expected callback path
    - does not contain user information or a fragment
- Preserves the existing `:<port>` listener behavior for callers using
`localhost`, avoiding a backward-incompatible single-address-family
change.

# Additional Changes

- Updates the client examples to use `127.0.0.1`, avoiding `localhost`
address-family ambiguity.
- Renames the `StartServer` parameter from `port` to `address` to
reflect that it receives a complete listening address.
- Adds tests covering IPv4, IPv6, existing `localhost` behavior, missing
and mismatched ports, non-loopback hosts, hostname lookalikes, HTTPS,
and callback path mismatches.

# Additional Context

Callers using an explicit loopback IP now get deterministic
address-family behavior. Existing callers using `localhost` retain the
previous wildcard listener behavior for compatibility.

Chromium resolves `localhost` to both IPv6 and IPv4, placing the IPv6
loopback address first. This can be observed on macOS by starting
separate IPv6 and IPv4 listeners.

In the first terminal:

```console
$ nc -k -6 -l 3000
```

In the second terminal:

```console
$ nc -k -4 -l 3000
```

Both listeners can be confirmed with:

```console
$ lsof -n -P -i:3000
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
nc      61660 suku    3u  IPv4 0xaf57491278098f95      0t0  TCP *:3000 (LISTEN)
nc      61696 suku    3u  IPv6 0x86b12b3afee37ced      0t0  TCP *:3000 (LISTEN)
```

Opening `http://localhost:3000` in Chromium connects to the IPv6
listener. Because that connection succeeds, Chromium does not need to
fall back to IPv4. This demonstrates that `localhost` is not equivalent
to explicitly selecting `127.0.0.1`.

Chromium's
[`ResolveLocalHostname`](https://source.chromium.org/chromium/chromium/src/+/c70cbba2e0b73e622ff5899294e76974be0083f2:net/dns/host_resolver_manager.cc;l=332)
adds the IPv6 loopback address before the IPv4 loopback address.

This is a callback reliability and loopback-hardening change. It does
not claim that every wildcard Go listener encounters an address-family
failure.

v3.48.0

Toggle v3.48.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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>

v4.0.0-next.3

Toggle v4.0.0-next.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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>

v3.47.9

Toggle v3.47.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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>

v4.0.0-next.2

Toggle v4.0.0-next.2's commit message
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>

v3.47.8

Toggle v3.47.8's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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>