Compare commits

...

71 commits

Author SHA1 Message Date
653b807f5d replace github url 2025-06-20 09:45:28 +02:00
29d69ca2e0 add function to marshal aud into a string if the array has a len of 1, to comply with rfc 2025-06-20 09:39:40 +02:00
53c4d07b45 remove actions 2025-06-20 08:56:29 +02:00
154fbe6420 Revert "feat(op): always verify code challenge when available (#721)"
Some checks failed
Code scanning - action / CodeQL-Build (push) Failing after 2m48s
Release / Go 1.23 test (push) Has been cancelled
Release / Go 1.24 test (push) Has been cancelled
Release / release (push) Has been cancelled
Breaks OIDC for some not yet updated applications, that we use.

This reverts commit c51628ea27.
2025-06-20 08:44:27 +02:00
Fabienne Bühler
d6e37fa741
Merge pull request #758 from zitadel/hifabienne-patch-1
chore: update issue templates
2025-06-17 14:32:55 +02:00
Fabienne Bühler
8e1e5174fd
Delete .github/ISSUE_TEMPLATE/proposal.yaml 2025-06-17 11:17:14 +02:00
Fabienne Bühler
5618487a88
Update and rename improvement.yaml to enhancement.yaml 2025-06-17 11:16:34 +02:00
Fabienne Bühler
187878de63
update docs issue template, add type 2025-06-17 11:15:26 +02:00
Fabienne Bühler
e127c66db2
chore: update issue templates 2025-06-17 11:14:09 +02:00
dependabot[bot]
e1415ef2f3
chore(deps): bump golang.org/x/text from 0.25.0 to 0.26.0 (#755)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.25.0 to 0.26.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 09:50:55 +02:00
Livio Spring
f94bd541d7
feat: update end session request to pass all params according to specification (#754)
* feat: update end session request to pass all params according to specification

* register encoder
2025-06-05 13:19:51 +02:00
dependabot[bot]
7d57aaa999
chore(deps): bump codecov/codecov-action from 5.4.2 to 5.4.3 (#751)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.4.2 to 5.4.3.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.4.2...v5.4.3)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 5.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-20 15:22:02 +03:00
dependabot[bot]
668fb0d37a
chore(deps): bump golang.org/x/text from 0.24.0 to 0.25.0 (#742)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.24.0 to 0.25.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-08 08:04:53 +02:00
dependabot[bot]
4ed4d257ab
chore(deps): bump golang.org/x/oauth2 from 0.29.0 to 0.30.0 (#743)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-08 08:00:26 +02:00
Ayato
4f0ed79c0a
fix(op): Add mitigation for PKCE Downgrade Attack (#741)
* fix(op): Add mitigation for PKCE downgrade attack

* chore(op): add test for PKCE verification
2025-04-29 14:33:31 +00:00
Masahito Osako
5913c5a074
feat: enhance authentication response handling (#728)
- Introduced CodeResponseType struct to encapsulate response data.
- Added handleFormPostResponse and handleRedirectResponse functions to manage different response modes.
- Created BuildAuthResponseCodeResponsePayload and BuildAuthResponseCallbackURL functions for better modularity in response generation.
2025-04-29 14:17:28 +00:00
dependabot[bot]
b917cdc2e3
chore(deps): bump codecov/codecov-action from 5.4.0 to 5.4.2 (#737)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.4.0 to 5.4.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.4.0...v5.4.2)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 5.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 11:13:43 +02:00
dependabot[bot]
cb3ec3ac5f
chore(deps): bump golang.org/x/net from 0.36.0 to 0.38.0 (#739)
* chore(deps): bump golang.org/x/net from 0.36.0 to 0.38.0

Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* update runner to ubuntu 24.04

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Livio Spring <livio.a@gmail.com>
2025-04-22 11:05:39 +02:00
dependabot[bot]
7cc5fb6568
chore(deps): bump golang.org/x/text from 0.23.0 to 0.24.0 (#733)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.23.0 to 0.24.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.23.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 12:05:26 +00:00
dependabot[bot]
92972fd30f
chore(deps): bump golang.org/x/oauth2 from 0.28.0 to 0.29.0 (#734)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.28.0 to 0.29.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-09 15:03:06 +03:00
Ayato
c51628ea27
feat(op): always verify code challenge when available (#721)
Finally the RFC Best Current Practice for OAuth 2.0 Security has been approved.

According to the RFC:

> Authorization servers MUST support PKCE [RFC7636].
> 
> If a client sends a valid PKCE code_challenge parameter in the authorization request, the authorization server MUST enforce the correct usage of code_verifier at the token endpoint.

Isn’t it time we strengthen PKCE support a bit more?

This PR updates the logic so that PKCE is always verified, even when the Auth Method is not "none".
2025-03-24 18:00:04 +02:00
dependabot[bot]
7096406e71
chore(deps): bump github.com/zitadel/schema from 1.3.0 to 1.3.1 (#731)
Bumps [github.com/zitadel/schema](https://github.com/zitadel/schema) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/zitadel/schema/releases)
- [Changelog](https://github.com/zitadel/schema/blob/main/.releaserc.js)
- [Commits](https://github.com/zitadel/schema/compare/v1.3.0...v1.3.1)

---
updated-dependencies:
- dependency-name: github.com/zitadel/schema
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 12:19:20 +02:00
dependabot[bot]
c91db9e47b
chore(deps): bump github.com/zitadel/logging from 0.6.1 to 0.6.2 (#730)
Bumps [github.com/zitadel/logging](https://github.com/zitadel/logging) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/zitadel/logging/releases)
- [Changelog](https://github.com/zitadel/logging/blob/main/.releaserc.js)
- [Commits](https://github.com/zitadel/logging/compare/v0.6.1...v0.6.2)

---
updated-dependencies:
- dependency-name: github.com/zitadel/logging
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 12:11:07 +02:00
Iraq
f648c61cab
Merge pull request #729 from zitadel/update-go-version
chore: run 'go mod tidy'
2025-03-23 16:49:50 +00:00
Iraq Jaber
30acdaf63a chore: run 'go mod tidy' 2025-03-23 16:27:57 +00:00
dependabot[bot]
aeda5d7178
chore(deps): bump golang.org/x/text from 0.22.0 to 0.23.0 (#723)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.22.0 to 0.23.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:05:10 +00:00
dependabot[bot]
f3ee647005
chore(deps): bump golang.org/x/net from 0.33.0 to 0.36.0 (#727)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 12:02:56 +02:00
dependabot[bot]
c401ad6cb8
chore(deps): bump golang.org/x/oauth2 from 0.26.0 to 0.28.0 (#724)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.26.0 to 0.28.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.26.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 07:46:07 +01:00
Iraq
2c64de821d
chore: updating go to 1.24 (#726)
* chore: updating go to 1.24

* fixup! chore: updating go to 1.24

* fixup! fixup! chore: updating go to 1.24

* fix device test (drop read error)

* drop older go versions

* drop unrelated formatter changes

---------

Co-authored-by: Iraq Jaber <IraqJaber@gmail.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
2025-03-14 16:12:26 +01:00
Tim Möhlmann
efd6fdad7a
fix: ignore empty json strings for locale (#678)
* Revert "fix: ignore all unmarshal errors from locale (#673)"

This reverts commit fbf009fe75.

* fix: ignore empty json strings for locale
2025-03-14 10:30:08 +00:00
BitMasher
7a767d8568
feat: add CanGetPrivateClaimsFromRequest interface (#717) 2025-03-12 14:00:29 +02:00
dependabot[bot]
eb2f912c5e
chore(deps): bump codecov/codecov-action from 5.3.1 to 5.4.0 (#722)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.3.1...v5.4.0)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 16:37:54 +01:00
dependabot[bot]
6a80712fbe
chore(deps): bump github.com/go-jose/go-jose/v4 from 4.0.4 to 4.0.5 (#716)
Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.0.4 to 4.0.5.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v4.0.4...v4.0.5)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 12:00:02 +02:00
minami yoshihiko
4ef9529012
feat: support for session_state (#712)
* add default signature algorithm

* implements session_state in auth_request.go

* add test

* Update pkg/op/auth_request.go

link to the standard

Co-authored-by: Tim Möhlmann <muhlemmer@gmail.com>

* add check_session_iframe

---------

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
Co-authored-by: Tim Möhlmann <muhlemmer@gmail.com>
2025-02-24 10:50:38 +00:00
Steve Ruckdashel
eb98343a65
fix: migrate deprecated io/ioutil.ReadFile to os.ReadFile (#714) 2025-02-21 09:52:02 +00:00
mqf20
add254f60c
docs(example): fixed creation of refresh token (#711)
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
2025-02-19 14:44:34 +02:00
mqf20
b1e5aca629
docs(example): check and extend refresh token expiration (#698)
* extend refresh token expiration

* check refresh token expiration

* check refresh token expiration (fixed logic)

* formatting

---------

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
2025-02-13 11:48:04 +00:00
mqf20
c03a8c59ca
docs(example): check access token expiration (#702) 2025-02-13 11:34:29 +00:00
mqf20
37dd41e49b
docs(example): simplified deletion (#699)
* simplified deletion

* added docs
2025-02-13 11:26:00 +00:00
mqf20
03e5ff8345
docs(example): add auth time (#700) 2025-02-13 11:23:44 +00:00
dependabot[bot]
c3c1bd3a40
chore(deps): bump github.com/go-chi/chi/v5 from 5.2.0 to 5.2.1 (#706)
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 13:45:18 +02:00
dependabot[bot]
0d46df908e
chore(deps): bump golang.org/x/text from 0.21.0 to 0.22.0 (#708)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 10:11:18 +00:00
dependabot[bot]
4250aad1f7
chore(deps): bump golang.org/x/oauth2 from 0.25.0 to 0.26.0 (#707)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 12:08:45 +02:00
dependabot[bot]
8c9a536058
chore(deps): bump codecov/codecov-action from 5.1.2 to 5.3.1 (#703)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.1.2 to 5.3.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.1.2...v5.3.1)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-28 10:29:28 +02:00
dependabot[bot]
24c96c361d
chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.8.0 to 4.8.1 (#701)
Bumps [github.com/bmatcuk/doublestar/v4](https://github.com/bmatcuk/doublestar) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/bmatcuk/doublestar/releases)
- [Commits](https://github.com/bmatcuk/doublestar/compare/v4.8.0...v4.8.1)

---
updated-dependencies:
- dependency-name: github.com/bmatcuk/doublestar/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 17:37:23 +02:00
Ramon
de2fd41f40
fix: allow native clients to use https:// on localhost redirects (#691) 2025-01-17 13:53:19 +00:00
dependabot[bot]
867a4806fd
chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.7.1 to 4.8.0 (#696)
Bumps [github.com/bmatcuk/doublestar/v4](https://github.com/bmatcuk/doublestar) from 4.7.1 to 4.8.0.
- [Release notes](https://github.com/bmatcuk/doublestar/releases)
- [Commits](https://github.com/bmatcuk/doublestar/compare/v4.7.1...v4.8.0)

---
updated-dependencies:
- dependency-name: github.com/bmatcuk/doublestar/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-17 14:51:01 +01:00
dependabot[bot]
1f6a0d5d89
chore(deps): bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#695)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 10:47:02 +02:00
Danila Fominykh
a0f67c0b4b
feat: add redirect URI-s ENV setting to web clients (#693)
Co-authored-by: FominykhDG <FominykhDG@cloudx.group>
2025-01-03 08:27:01 +00:00
Stefan Benz
8d971dcad8
chore: bump dependencies (#694) 2024-12-30 12:47:05 +02:00
dependabot[bot]
6c90652dfb
chore(deps): bump codecov/codecov-action from 5.1.1 to 5.1.2 (#692)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 11:00:57 +02:00
dependabot[bot]
b36a8e2ec1
chore(deps): bump github.com/go-chi/chi/v5 from 5.1.0 to 5.2.0 (#689)
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.1.0...v5.2.0)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 20:27:45 +02:00
dependabot[bot]
9a93b7c70d
chore(deps): bump golang.org/x/crypto from 0.25.0 to 0.31.0 (#688)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.25.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.25.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 11:33:24 +00:00
dependabot[bot]
cf6ce69d79
chore(deps): bump codecov/codecov-action from 5.0.7 to 5.1.1 (#687)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.0.7 to 5.1.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.0.7...v5.1.1)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 14:16:13 +01:00
dependabot[bot]
2513e21531
chore(deps): bump golang.org/x/text from 0.20.0 to 0.21.0 (#686)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.20.0 to 0.21.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 08:42:45 +01:00
dependabot[bot]
057601ff3f
chore(deps): bump codecov/codecov-action from 5.0.2 to 5.0.7 (#685)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.0.2 to 5.0.7.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5.0.2...v5.0.7)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 11:41:27 +02:00
dependabot[bot]
67bd2f5720
chore(deps): bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (#684)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.9.0 to 1.10.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 10:55:33 +02:00
dependabot[bot]
e2de68a7dd
chore(deps): bump github.com/jeremija/gosubmit from 0.2.7 to 0.2.8 (#683)
Bumps [github.com/jeremija/gosubmit](https://github.com/jeremija/gosubmit) from 0.2.7 to 0.2.8.
- [Commits](https://github.com/jeremija/gosubmit/compare/v0.2.7...v0.2.8)

---
updated-dependencies:
- dependency-name: github.com/jeremija/gosubmit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 10:04:43 +02:00
dependabot[bot]
a7833f828c
chore(deps): bump codecov/codecov-action from 4.6.0 to 5.0.2 (#682)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.6.0 to 5.0.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4.6.0...v5.0.2)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-19 12:59:21 +02:00
isegura-eos-eng
6d20928028
refactor: mark pkg/strings as deprecated in favor of stdlib (#680)
* refactor: mark pkg/strings as deprecated in favor of stdlib

* format: reword deprecate notice and use doc links
2024-11-15 18:47:32 +02:00
Tim Möhlmann
1464268851
chore(deps): upgrade go to v1.23 (#681) 2024-11-15 07:26:03 +01:00
isegura-eos-eng
897c720070
fix(op): add scope to access token scope (#664) 2024-11-13 08:49:55 +00:00
Kevin Schoonover
8afb8b8d5f
feat(pkg/op): allow custom SupportedScopes (#675)
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
2024-11-12 15:06:24 +00:00
dependabot[bot]
87ab011157
chore(deps): bump golang.org/x/oauth2 from 0.23.0 to 0.24.0 (#676)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.23.0 to 0.24.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.23.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 12:55:25 +02:00
dependabot[bot]
f194951e61
chore(deps): bump golang.org/x/text from 0.19.0 to 0.20.0 (#677)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.19.0 to 0.20.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 12:52:23 +02:00
David Sharnoff
fbf009fe75
fix: ignore all unmarshal errors from locale (#673) 2024-11-01 10:53:28 +02:00
Livio Spring
f1e4cb2245
feat(OP): add back channel logout support (#671)
* feat: add configuration support for back channel logout

* logout token

* indicate back channel logout support in discovery endpoint
2024-10-30 08:44:31 +00:00
lanseg
24869d2811
feat(example): Allow configuring some parameters with env variables (#663)
Co-authored-by: Andrey Rusakov <andrey.rusakov@camptocamp.com>
2024-10-21 20:59:28 +02:00
dependabot[bot]
9f7cbb0dbf
chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.6.1 to 4.7.1 (#666)
Bumps [github.com/bmatcuk/doublestar/v4](https://github.com/bmatcuk/doublestar) from 4.6.1 to 4.7.1.
- [Release notes](https://github.com/bmatcuk/doublestar/releases)
- [Commits](https://github.com/bmatcuk/doublestar/compare/v4.6.1...v4.7.1)

---
updated-dependencies:
- dependency-name: github.com/bmatcuk/doublestar/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-15 14:12:28 +03:00
dependabot[bot]
5ae555e191
chore(deps): bump codecov/codecov-action from 4.5.0 to 4.6.0 (#662)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.5.0 to 4.6.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4.5.0...v4.6.0)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-08 12:00:43 +03:00
dependabot[bot]
2abae36bd9
chore(deps): bump golang.org/x/text from 0.18.0 to 0.19.0 (#661)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.18.0 to 0.19.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 18:39:28 +03:00
125 changed files with 1487 additions and 494 deletions

View file

@ -2,6 +2,7 @@ name: Bug Report
description: "Create a bug report to help us improve ZITADEL. Click [here](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#product-management) to see how we process your issue." description: "Create a bug report to help us improve ZITADEL. Click [here](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#product-management) to see how we process your issue."
title: "[Bug]: " title: "[Bug]: "
labels: ["bug"] labels: ["bug"]
type: Bug
body: body:
- type: markdown - type: markdown
attributes: attributes:

View file

@ -1,6 +1,7 @@
name: 📄 Documentation name: 📄 Documentation
description: Create an issue for missing or wrong documentation. description: Create an issue for missing or wrong documentation.
labels: ["docs"] labels: ["docs"]
type: task
body: body:
- type: markdown - type: markdown
attributes: attributes:

View file

@ -1,11 +1,12 @@
name: 🛠️ Improvement name: 🛠️ Improvement
description: "Create an new issue for an improvment in ZITADEL" description: "Create an new issue for an improvment in ZITADEL"
labels: ["improvement"] labels: ["enhancement"]
type: enhancement
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Thanks for taking the time to fill out this improvement request Thanks for taking the time to fill out this proposal / feature reqeust
- type: checkboxes - type: checkboxes
id: preflight id: preflight
attributes: attributes:

View file

@ -14,11 +14,11 @@ on:
jobs: jobs:
test: test:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
go: ['1.21', '1.22'] go: ['1.23', '1.24']
name: Go ${{ matrix.go }} test name: Go ${{ matrix.go }} test
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -27,12 +27,12 @@ jobs:
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
- run: go test -race -v -coverprofile=profile.cov -coverpkg=./pkg/... ./pkg/... - run: go test -race -v -coverprofile=profile.cov -coverpkg=./pkg/... ./pkg/...
- uses: codecov/codecov-action@v4.5.0 - uses: codecov/codecov-action@v5.4.3
with: with:
file: ./profile.cov file: ./profile.cov
name: codecov-go name: codecov-go
release: release:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
needs: [test] needs: [test]
if: ${{ github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next' }} if: ${{ github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next' }}
env: env:

View file

@ -1,44 +0,0 @@
name: 💡 Proposal / Feature request
description: "Create an issue for a feature request/proposal."
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this proposal / feature reqeust
- type: checkboxes
id: preflight
attributes:
label: Preflight Checklist
options:
- label:
I could not find a solution in the existing issues, docs, nor discussions
required: true
- label:
I have joined the [ZITADEL chat](https://zitadel.com/chat)
- type: textarea
id: problem
attributes:
label: Describe your problem
description: Please describe your problem this proposal / feature is supposed to solve.
placeholder: Describe the problem you have.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe your ideal solution
description: Which solution do you propose?
placeholder: As a [type of user], I want [some goal] so that [some reason].
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Which version of the OIDC Library are you using.
- type: textarea
id: additional
attributes:
label: Additional Context
description: Please add any other infos that could be useful.

View file

@ -21,6 +21,7 @@ Whenever possible we tried to reuse / extend existing packages like `OAuth2 for
## Basic Overview ## Basic Overview
The most important packages of the library: The most important packages of the library:
<pre> <pre>
/pkg /pkg
/client clients using the OP for retrieving, exchanging and verifying tokens /client clients using the OP for retrieving, exchanging and verifying tokens
@ -37,7 +38,6 @@ The most important packages of the library:
/server examples of an OpenID Provider implementations (including dynamic) with some very basic login UI /server examples of an OpenID Provider implementations (including dynamic) with some very basic login UI
</pre> </pre>
### Semver ### Semver
This package uses [semver](https://semver.org/) for [releases](https://github.com/zitadel/oidc/releases). Major releases ship breaking changes. Starting with the `v2` to `v3` increment we provide an [upgrade guide](UPGRADING.md) to ease migration to a newer version. This package uses [semver](https://semver.org/) for [releases](https://github.com/zitadel/oidc/releases). Major releases ship breaking changes. Starting with the `v2` to `v3` increment we provide an [upgrade guide](UPGRADING.md) to ease migration to a newer version.
@ -60,20 +60,54 @@ CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://localhost:9998/ SCOPES="openid
- the OP will redirect you to the client app, which displays the user info - the OP will redirect you to the client app, which displays the user info
for the dynamic issuer, just start it with: for the dynamic issuer, just start it with:
```bash ```bash
go run github.com/zitadel/oidc/v3/example/server/dynamic go run github.com/zitadel/oidc/v3/example/server/dynamic
``` ```
the oidc web client above will still work, but if you add `oidc.local` (pointing to 127.0.0.1) in your hosts file you can also start it with: the oidc web client above will still work, but if you add `oidc.local` (pointing to 127.0.0.1) in your hosts file you can also start it with:
```bash ```bash
CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://oidc.local:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v3/example/client/app CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://oidc.local:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v3/example/client/app
``` ```
> Note: Usernames are suffixed with the hostname (`test-user@localhost` or `test-user@oidc.local`) > Note: Usernames are suffixed with the hostname (`test-user@localhost` or `test-user@oidc.local`)
### Server configuration
Example server allows extra configuration using environment variables and could be used for end to
end testing of your services.
| Name | Format | Description |
| ------------ | -------------------------------- | ------------------------------------- |
| PORT | Number between 1 and 65535 | OIDC listen port |
| REDIRECT_URI | Comma-separated URIs | List of allowed redirect URIs |
| USERS_FILE | Path to json in local filesystem | Users with their data and credentials |
Here is json equivalent for one of the default users
```json
{
"id2": {
"ID": "id2",
"Username": "test-user2",
"Password": "verysecure",
"FirstName": "Test",
"LastName": "User2",
"Email": "test-user2@zitadel.ch",
"EmailVerified": true,
"Phone": "",
"PhoneVerified": false,
"PreferredLanguage": "DE",
"IsAdmin": false
}
}
```
## Features ## Features
| | Relying party | OpenID Provider | Specification | | | Relying party | OpenID Provider | Specification |
| -------------------- | ------------- | --------------- | ----------------------------------------- | | -------------------- | ------------- | --------------- | -------------------------------------------- |
| Code Flow | yes | yes | OpenID Connect Core 1.0, [Section 3.1][1] | | Code Flow | yes | yes | OpenID Connect Core 1.0, [Section 3.1][1] |
| Implicit Flow | no[^1] | yes | OpenID Connect Core 1.0, [Section 3.2][2] | | Implicit Flow | no[^1] | yes | OpenID Connect Core 1.0, [Section 3.2][2] |
| Hybrid Flow | no | not yet | OpenID Connect Core 1.0, [Section 3.3][3] | | Hybrid Flow | no | not yet | OpenID Connect Core 1.0, [Section 3.3][3] |
@ -85,18 +119,20 @@ CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://oidc.local:9998/ SCOPES="openid
| Token Exchange | yes | yes | [RFC 8693][9] | | Token Exchange | yes | yes | [RFC 8693][9] |
| Device Authorization | yes | yes | [RFC 8628][10] | | Device Authorization | yes | yes | [RFC 8628][10] |
| mTLS | not yet | not yet | [RFC 8705][11] | | mTLS | not yet | not yet | [RFC 8705][11] |
| Back-Channel Logout | not yet | yes | OpenID Connect [Back-Channel Logout][12] 1.0 |
[1]: <https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth> "3.1. Authentication using the Authorization Code Flow" [1]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth "3.1. Authentication using the Authorization Code Flow"
[2]: <https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth> "3.2. Authentication using the Implicit Flow" [2]: https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth "3.2. Authentication using the Implicit Flow"
[3]: <https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth> "3.3. Authentication using the Hybrid Flow" [3]: https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth "3.3. Authentication using the Hybrid Flow"
[4]: <https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication> "9. Client Authentication" [4]: https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication "9. Client Authentication"
[5]: <https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens> "12. Using Refresh Tokens" [5]: https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens "12. Using Refresh Tokens"
[6]: <https://openid.net/specs/openid-connect-discovery-1_0.html> "OpenID Connect Discovery 1.0 incorporating errata set 1" [6]: https://openid.net/specs/openid-connect-discovery-1_0.html "OpenID Connect Discovery 1.0 incorporating errata set 1"
[7]: <https://www.rfc-editor.org/rfc/rfc7523.html> "JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants" [7]: https://www.rfc-editor.org/rfc/rfc7523.html "JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants"
[8]: <https://www.rfc-editor.org/rfc/rfc7636.html> "Proof Key for Code Exchange by OAuth Public Clients" [8]: https://www.rfc-editor.org/rfc/rfc7636.html "Proof Key for Code Exchange by OAuth Public Clients"
[9]: <https://www.rfc-editor.org/rfc/rfc8693.html> "OAuth 2.0 Token Exchange" [9]: https://www.rfc-editor.org/rfc/rfc8693.html "OAuth 2.0 Token Exchange"
[10]: <https://www.rfc-editor.org/rfc/rfc8628.html> "OAuth 2.0 Device Authorization Grant" [10]: https://www.rfc-editor.org/rfc/rfc8628.html "OAuth 2.0 Device Authorization Grant"
[11]: <https://www.rfc-editor.org/rfc/rfc8705.html> "OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens" [11]: https://www.rfc-editor.org/rfc/rfc8705.html "OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens"
[12]: https://openid.net/specs/openid-connect-backchannel-1_0.html "OpenID Connect Back-Channel Logout 1.0 incorporating errata set 1"
## Contributors ## Contributors
@ -120,9 +156,9 @@ Versions that also build are marked with :warning:.
| Version | Supported | | Version | Supported |
| ------- | ------------------ | | ------- | ------------------ |
| <1.21 | :x: | | <1.23 | :x: |
| 1.21 | :white_check_mark: | | 1.23 | :white_check_mark: |
| 1.22 | :white_check_mark: | | 1.24 | :white_check_mark: |
## Why another library ## Why another library
@ -153,5 +189,4 @@ Unless required by applicable law or agreed to in writing, software distributed
AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. language governing permissions and limitations under the License.
[^1]: https://github.com/zitadel/oidc/issues/135#issuecomment-950563892 [^1]: https://github.com/zitadel/oidc/issues/135#issuecomment-950563892

View file

@ -13,8 +13,8 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/zitadel/oidc/v3/pkg/client/rs" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rs"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
const ( const (

View file

@ -14,10 +14,10 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
var ( var (

View file

@ -45,8 +45,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
) )
var ( var (

View file

@ -10,10 +10,10 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
githubOAuth "golang.org/x/oauth2/github" githubOAuth "golang.org/x/oauth2/github"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/client/rp/cli" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp/cli"
"github.com/zitadel/oidc/v3/pkg/http" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
var ( var (

View file

@ -13,7 +13,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/pkg/client/profile" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/profile"
) )
var client = http.DefaultClient var client = http.DefaultClient

View file

@ -0,0 +1,40 @@
package config
import (
"os"
"strings"
)
const (
// default port for the http server to run
DefaultIssuerPort = "9998"
)
type Config struct {
Port string
RedirectURI []string
UsersFile string
}
// FromEnvVars loads configuration parameters from environment variables.
// If there is no such variable defined, then use default values.
func FromEnvVars(defaults *Config) *Config {
if defaults == nil {
defaults = &Config{}
}
cfg := &Config{
Port: defaults.Port,
RedirectURI: defaults.RedirectURI,
UsersFile: defaults.UsersFile,
}
if value, ok := os.LookupEnv("PORT"); ok {
cfg.Port = value
}
if value, ok := os.LookupEnv("USERS_FILE"); ok {
cfg.UsersFile = value
}
if value, ok := os.LookupEnv("REDIRECT_URI"); ok {
cfg.RedirectURI = strings.Split(value, ",")
}
return cfg
}

View file

@ -0,0 +1,77 @@
package config
import (
"fmt"
"os"
"testing"
)
func TestFromEnvVars(t *testing.T) {
for _, tc := range []struct {
name string
env map[string]string
defaults *Config
want *Config
}{
{
name: "no vars, no default values",
env: map[string]string{},
want: &Config{},
},
{
name: "no vars, only defaults",
env: map[string]string{},
defaults: &Config{
Port: "6666",
UsersFile: "/default/user/path",
RedirectURI: []string{"re", "direct", "uris"},
},
want: &Config{
Port: "6666",
UsersFile: "/default/user/path",
RedirectURI: []string{"re", "direct", "uris"},
},
},
{
name: "overriding default values",
env: map[string]string{
"PORT": "1234",
"USERS_FILE": "/path/to/users",
"REDIRECT_URI": "http://redirect/redirect",
},
defaults: &Config{
Port: "6666",
UsersFile: "/default/user/path",
RedirectURI: []string{"re", "direct", "uris"},
},
want: &Config{
Port: "1234",
UsersFile: "/path/to/users",
RedirectURI: []string{"http://redirect/redirect"},
},
},
{
name: "multiple redirect uris",
env: map[string]string{
"REDIRECT_URI": "http://host_1,http://host_2,http://host_3",
},
want: &Config{
RedirectURI: []string{
"http://host_1", "http://host_2", "http://host_3",
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
os.Clearenv()
for k, v := range tc.env {
os.Setenv(k, v)
}
cfg := FromEnvVars(tc.defaults)
if fmt.Sprint(cfg) != fmt.Sprint(tc.want) {
t.Errorf("Expected FromEnvVars()=%q, but got %q", tc.want, cfg)
}
})
}
}

View file

@ -8,7 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
const ( const (

View file

@ -10,8 +10,8 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/oidc/v3/example/server/storage" "git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
const ( const (

View file

@ -8,10 +8,10 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/gorilla/securecookie" "github.com/gorilla/securecookie"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/zitadel/oidc/v3/pkg/op"
) )
type deviceAuthenticate interface { type deviceAuthenticate interface {

View file

@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/zitadel/oidc/v3/pkg/op"
) )
type login struct { type login struct {

View file

@ -12,7 +12,7 @@ import (
"github.com/zitadel/logging" "github.com/zitadel/logging"
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
const ( const (

View file

@ -5,44 +5,54 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"os" "os"
"strings"
"github.com/zitadel/oidc/v3/example/server/exampleop" "git.christmann.info/LARA/zitadel-oidc/v3/example/server/config"
"github.com/zitadel/oidc/v3/example/server/storage" "git.christmann.info/LARA/zitadel-oidc/v3/example/server/exampleop"
"git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
) )
func getUserStore(cfg *config.Config) (storage.UserStore, error) {
if cfg.UsersFile == "" {
return storage.NewUserStore(fmt.Sprintf("http://localhost:%s/", cfg.Port)), nil
}
return storage.StoreFromFile(cfg.UsersFile)
}
func main() { func main() {
//we will run on :9998 cfg := config.FromEnvVars(&config.Config{Port: "9998"})
port := "9998"
//which gives us the issuer: http://localhost:9998/
issuer := fmt.Sprintf("http://localhost:%s/", port)
storage.RegisterClients(
storage.NativeClient("native", strings.Split(os.Getenv("REDIRECT_URI"), ",")...),
storage.WebClient("web", "secret"),
storage.WebClient("api", "secret"),
)
// the OpenIDProvider interface needs a Storage interface handling various checks and state manipulations
// this might be the layer for accessing your database
// in this example it will be handled in-memory
storage := storage.NewStorage(storage.NewUserStore(issuer))
logger := slog.New( logger := slog.New(
slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
AddSource: true, AddSource: true,
Level: slog.LevelDebug, Level: slog.LevelDebug,
}), }),
) )
//which gives us the issuer: http://localhost:9998/
issuer := fmt.Sprintf("http://localhost:%s/", cfg.Port)
storage.RegisterClients(
storage.NativeClient("native", cfg.RedirectURI...),
storage.WebClient("web", "secret", cfg.RedirectURI...),
storage.WebClient("api", "secret", cfg.RedirectURI...),
)
// the OpenIDProvider interface needs a Storage interface handling various checks and state manipulations
// this might be the layer for accessing your database
// in this example it will be handled in-memory
store, err := getUserStore(cfg)
if err != nil {
logger.Error("cannot create UserStore", "error", err)
os.Exit(1)
}
storage := storage.NewStorage(store)
router := exampleop.SetupServer(issuer, storage, logger, false) router := exampleop.SetupServer(issuer, storage, logger, false)
server := &http.Server{ server := &http.Server{
Addr: ":" + port, Addr: ":" + cfg.Port,
Handler: router, Handler: router,
} }
logger.Info("server listening, press ctrl+c to stop", "addr", fmt.Sprintf("http://localhost:%s/", port)) logger.Info("server listening, press ctrl+c to stop", "addr", issuer)
err := server.ListenAndServe() if server.ListenAndServe() != http.ErrServerClosed {
if err != http.ErrServerClosed {
logger.Error("server terminated", "error", err) logger.Error("server terminated", "error", err)
os.Exit(1) os.Exit(1)
} }

View file

@ -3,8 +3,8 @@ package storage
import ( import (
"time" "time"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
var ( var (

View file

@ -6,8 +6,8 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
const ( const (
@ -164,6 +164,15 @@ func authRequestToInternal(authReq *oidc.AuthRequest, userID string) *AuthReques
} }
} }
type AuthRequestWithSessionState struct {
*AuthRequest
SessionState string
}
func (a *AuthRequestWithSessionState) GetSessionState() string {
return a.SessionState
}
type OIDCCodeChallenge struct { type OIDCCodeChallenge struct {
Challenge string Challenge string
Method string Method string

View file

@ -14,8 +14,8 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
// serviceKey1 is a public key which will be used for the JWT Profile Authorization Grant // serviceKey1 is a public key which will be used for the JWT Profile Authorization Grant
@ -151,6 +151,9 @@ func (s *Storage) CheckUsernamePassword(username, password, id string) error {
// in this example we'll simply check the username / password and set a boolean to true // in this example we'll simply check the username / password and set a boolean to true
// therefore we will also just check this boolean if the request / login has been finished // therefore we will also just check this boolean if the request / login has been finished
request.done = true request.done = true
request.authTime = time.Now()
return nil return nil
} }
return fmt.Errorf("username or password wrong") return fmt.Errorf("username or password wrong")
@ -295,15 +298,19 @@ func (s *Storage) CreateAccessAndRefreshTokens(ctx context.Context, request op.T
// if we get here, the currentRefreshToken was not empty, so the call is a refresh token request // if we get here, the currentRefreshToken was not empty, so the call is a refresh token request
// we therefore will have to check the currentRefreshToken and renew the refresh token // we therefore will have to check the currentRefreshToken and renew the refresh token
refreshToken, refreshTokenID, err := s.renewRefreshToken(currentRefreshToken)
newRefreshToken = uuid.NewString()
accessToken, err := s.accessToken(applicationID, newRefreshToken, request.GetSubject(), request.GetAudience(), request.GetScopes())
if err != nil { if err != nil {
return "", "", time.Time{}, err return "", "", time.Time{}, err
} }
accessToken, err := s.accessToken(applicationID, refreshTokenID, request.GetSubject(), request.GetAudience(), request.GetScopes())
if err != nil { if err := s.renewRefreshToken(currentRefreshToken, newRefreshToken, accessToken.ID); err != nil {
return "", "", time.Time{}, err return "", "", time.Time{}, err
} }
return accessToken.ID, refreshToken, accessToken.Expiration, nil
return accessToken.ID, newRefreshToken, accessToken.Expiration, nil
} }
func (s *Storage) exchangeRefreshToken(ctx context.Context, request op.TokenExchangeRequest) (accessTokenID string, newRefreshToken string, expiration time.Time, err error) { func (s *Storage) exchangeRefreshToken(ctx context.Context, request op.TokenExchangeRequest) (accessTokenID string, newRefreshToken string, expiration time.Time, err error) {
@ -385,14 +392,9 @@ func (s *Storage) RevokeToken(ctx context.Context, tokenIDOrToken string, userID
if refreshToken.ApplicationID != clientID { if refreshToken.ApplicationID != clientID {
return oidc.ErrInvalidClient().WithDescription("token was not issued for this client") return oidc.ErrInvalidClient().WithDescription("token was not issued for this client")
} }
// if it is a refresh token, you will have to remove the access token as well
delete(s.refreshTokens, refreshToken.ID) delete(s.refreshTokens, refreshToken.ID)
for _, accessToken := range s.tokens { // if it is a refresh token, you will have to remove the access token as well
if accessToken.RefreshTokenID == refreshToken.ID { delete(s.tokens, refreshToken.AccessToken)
delete(s.tokens, accessToken.ID)
return nil
}
}
return nil return nil
} }
@ -488,6 +490,9 @@ func (s *Storage) SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserI
// return err // return err
// } // }
//} //}
if token.Expiration.Before(time.Now()) {
return fmt.Errorf("token is expired")
}
return s.setUserinfo(ctx, userinfo, token.Subject, token.ApplicationID, token.Scopes) return s.setUserinfo(ctx, userinfo, token.Subject, token.ApplicationID, token.Scopes)
} }
@ -594,33 +599,41 @@ func (s *Storage) createRefreshToken(accessToken *Token, amr []string, authTime
Audience: accessToken.Audience, Audience: accessToken.Audience,
Expiration: time.Now().Add(5 * time.Hour), Expiration: time.Now().Add(5 * time.Hour),
Scopes: accessToken.Scopes, Scopes: accessToken.Scopes,
AccessToken: accessToken.ID,
} }
s.refreshTokens[token.ID] = token s.refreshTokens[token.ID] = token
return token.Token, nil return token.Token, nil
} }
// renewRefreshToken checks the provided refresh_token and creates a new one based on the current // renewRefreshToken checks the provided refresh_token and creates a new one based on the current
func (s *Storage) renewRefreshToken(currentRefreshToken string) (string, string, error) { //
// [Refresh Token Rotation] is implemented.
//
// [Refresh Token Rotation]: https://www.rfc-editor.org/rfc/rfc6819#section-5.2.2.3
func (s *Storage) renewRefreshToken(currentRefreshToken, newRefreshToken, newAccessToken string) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
refreshToken, ok := s.refreshTokens[currentRefreshToken] refreshToken, ok := s.refreshTokens[currentRefreshToken]
if !ok { if !ok {
return "", "", fmt.Errorf("invalid refresh token") return fmt.Errorf("invalid refresh token")
} }
// deletes the refresh token and all access tokens which were issued based on this refresh token // deletes the refresh token
delete(s.refreshTokens, currentRefreshToken) delete(s.refreshTokens, currentRefreshToken)
for _, token := range s.tokens {
if token.RefreshTokenID == currentRefreshToken { // delete the access token which was issued based on this refresh token
delete(s.tokens, token.ID) delete(s.tokens, refreshToken.AccessToken)
break
} if refreshToken.Expiration.Before(time.Now()) {
return fmt.Errorf("expired refresh token")
} }
// creates a new refresh token based on the current one // creates a new refresh token based on the current one
token := uuid.NewString() refreshToken.Token = newRefreshToken
refreshToken.Token = token refreshToken.ID = newRefreshToken
refreshToken.ID = token refreshToken.Expiration = time.Now().Add(5 * time.Hour)
s.refreshTokens[token] = refreshToken refreshToken.AccessToken = newAccessToken
return token, refreshToken.ID, nil s.refreshTokens[newRefreshToken] = refreshToken
return nil
} }
// accessToken will store an access_token in-memory based on the provided information // accessToken will store an access_token in-memory based on the provided information

View file

@ -6,8 +6,8 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
type multiStorage struct { type multiStorage struct {

View file

@ -22,4 +22,5 @@ type RefreshToken struct {
ApplicationID string ApplicationID string
Expiration time.Time Expiration time.Time
Scopes []string Scopes []string
AccessToken string // Token.ID
} }

View file

@ -2,6 +2,8 @@ package storage
import ( import (
"crypto/rsa" "crypto/rsa"
"encoding/json"
"os"
"strings" "strings"
"golang.org/x/text/language" "golang.org/x/text/language"
@ -35,6 +37,18 @@ type userStore struct {
users map[string]*User users map[string]*User
} }
func StoreFromFile(path string) (UserStore, error) {
users := map[string]*User{}
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
if err := json.Unmarshal(data, &users); err != nil {
return nil, err
}
return userStore{users}, nil
}
func NewUserStore(issuer string) UserStore { func NewUserStore(issuer string) UserStore {
hostname := strings.Split(strings.Split(issuer, "://")[1], ":")[0] hostname := strings.Split(strings.Split(issuer, "://")[1], ":")[0]
return userStore{ return userStore{

View file

@ -0,0 +1,70 @@
package storage
import (
"os"
"path"
"reflect"
"testing"
"golang.org/x/text/language"
)
func TestStoreFromFile(t *testing.T) {
for _, tc := range []struct {
name string
pathToFile string
content string
want UserStore
wantErr bool
}{
{
name: "normal user file",
pathToFile: "userfile.json",
content: `{
"id1": {
"ID": "id1",
"EmailVerified": true,
"PreferredLanguage": "DE"
}
}`,
want: userStore{map[string]*User{
"id1": {
ID: "id1",
EmailVerified: true,
PreferredLanguage: language.German,
},
}},
},
{
name: "malformed file",
pathToFile: "whatever",
content: "not a json just a text",
wantErr: true,
},
{
name: "not existing file",
pathToFile: "what/ever/file",
wantErr: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
actualPath := path.Join(t.TempDir(), tc.pathToFile)
if tc.content != "" && tc.pathToFile != "" {
if err := os.WriteFile(actualPath, []byte(tc.content), 0666); err != nil {
t.Fatalf("cannot create file with test content: %q", tc.content)
}
}
result, err := StoreFromFile(actualPath)
if err != nil && !tc.wantErr {
t.Errorf("StoreFromFile(%q) returned unexpected error %q", tc.pathToFile, err)
} else if err == nil && tc.wantErr {
t.Errorf("StoreFromFile(%q) did not return an expected error", tc.pathToFile)
}
if !tc.wantErr && !reflect.DeepEqual(tc.want, result.(userStore)) {
t.Errorf("expected StoreFromFile(%q) = %v, but got %v",
tc.pathToFile, tc.want, result)
}
})
}
}

30
go.mod
View file

@ -1,26 +1,28 @@
module github.com/zitadel/oidc/v3 module git.christmann.info/LARA/zitadel-oidc/v3
go 1.21 go 1.23.7
toolchain go1.24.1
require ( require (
github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/bmatcuk/doublestar/v4 v4.8.1
github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/chi/v5 v5.2.1
github.com/go-jose/go-jose/v4 v4.0.4 github.com/go-jose/go-jose/v4 v4.0.5
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/go-github/v31 v31.0.0 github.com/google/go-github/v31 v31.0.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/securecookie v1.1.2 github.com/gorilla/securecookie v1.1.2
github.com/jeremija/gosubmit v0.2.7 github.com/jeremija/gosubmit v0.2.8
github.com/muhlemmer/gu v0.3.1 github.com/muhlemmer/gu v0.3.1
github.com/muhlemmer/httpforwarded v0.1.0 github.com/muhlemmer/httpforwarded v0.1.0
github.com/rs/cors v1.11.1 github.com/rs/cors v1.11.1
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
github.com/zitadel/logging v0.6.1 github.com/zitadel/logging v0.6.2
github.com/zitadel/schema v1.3.0 github.com/zitadel/schema v1.3.1
go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel v1.29.0
golang.org/x/oauth2 v0.23.0 golang.org/x/oauth2 v0.30.0
golang.org/x/text v0.18.0 golang.org/x/text v0.26.0
) )
require ( require (
@ -31,8 +33,8 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect
golang.org/x/crypto v0.25.0 // indirect golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.26.0 // indirect golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

52
go.sum
View file

@ -1,12 +1,12 @@
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@ -29,8 +29,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= github.com/jeremija/gosubmit v0.2.8 h1:mmSITBz9JxVtu8eqbN+zmmwX7Ij2RidQxhcwRVI4wqA=
github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI= github.com/jeremija/gosubmit v0.2.8/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
@ -47,13 +47,13 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y= github.com/zitadel/logging v0.6.2 h1:MW2kDDR0ieQynPZ0KIZPrh9ote2WkxfBif5QoARDQcU=
github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= github.com/zitadel/logging v0.6.2/go.mod h1:z6VWLWUkJpnNVDSLzrPSQSQyttysKZ6bCRongw0ROK4=
github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= github.com/zitadel/schema v1.3.1 h1:QT3kwiRIRXXLVAs6gCK/u044WmUVh6IlbLXUsn6yRQU=
github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= github.com/zitadel/schema v1.3.1/go.mod h1:071u7D2LQacy1HAN+YnMd/mx1qVE2isb0Mjeqg46xnU=
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
@ -62,19 +62,19 @@ go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt3
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -83,13 +83,13 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -101,8 +101,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -8,8 +8,8 @@ import (
"fmt" "fmt"
"os" "os"
tu "github.com/zitadel/oidc/v3/internal/testutil" tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
var custom = map[string]any{ var custom = map[string]any{

View file

@ -8,9 +8,9 @@ import (
"errors" "errors"
"time" "time"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
// KeySet implements oidc.Keys // KeySet implements oidc.Keys

View file

@ -15,9 +15,9 @@ import (
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/pkg/crypto" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/crypto"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
var ( var (

View file

@ -5,9 +5,9 @@ import (
"net/http" "net/http"
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
func TestDiscover(t *testing.T) { func TestDiscover(t *testing.T) {

View file

@ -23,14 +23,14 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/example/server/exampleop" "git.christmann.info/LARA/zitadel-oidc/v3/example/server/exampleop"
"github.com/zitadel/oidc/v3/example/server/storage" "git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/client/rs" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rs"
"github.com/zitadel/oidc/v3/pkg/client/tokenexchange" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/tokenexchange"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
var Logger = slog.New( var Logger = slog.New(

View file

@ -6,8 +6,8 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/pkg/http" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
// JWTProfileExchange handles the oauth2 jwt profile exchange // JWTProfileExchange handles the oauth2 jwt profile exchange

View file

@ -2,7 +2,7 @@ package client
import ( import (
"encoding/json" "encoding/json"
"io/ioutil" "os"
) )
const ( const (
@ -24,7 +24,7 @@ type KeyFile struct {
} }
func ConfigFromKeyFile(path string) (*KeyFile, error) { func ConfigFromKeyFile(path string) (*KeyFile, error) {
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -8,8 +8,8 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/pkg/client" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type TokenSource interface { type TokenSource interface {

View file

@ -4,9 +4,9 @@ import (
"context" "context"
"net/http" "net/http"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
const ( const (

View file

@ -1,7 +1,7 @@
package rp package rp
import ( import (
"github.com/zitadel/oidc/v3/pkg/oidc/grants/tokenexchange" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc/grants/tokenexchange"
) )
// DelegationTokenRequest is an implementation of TokenExchangeRequest // DelegationTokenRequest is an implementation of TokenExchangeRequest

View file

@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/zitadel/oidc/v3/pkg/client" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
func newDeviceClientCredentialsRequest(scopes []string, rp RelyingParty) (*oidc.ClientCredentialsRequest, error) { func newDeviceClientCredentialsRequest(scopes []string, rp RelyingParty) (*oidc.ClientCredentialsRequest, error) {

View file

@ -9,9 +9,9 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/zitadel/oidc/v3/pkg/client" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
func NewRemoteKeySet(client *http.Client, jwksURL string, opts ...func(*remoteKeySet)) oidc.KeySet { func NewRemoteKeySet(client *http.Client, jwksURL string, opts ...func(*remoteKeySet)) oidc.KeySet {

View file

@ -14,10 +14,10 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials" "golang.org/x/oauth2/clientcredentials"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/client"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
const ( const (

View file

@ -5,10 +5,10 @@ import (
"testing" "testing"
"time" "time"
tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
tu "github.com/zitadel/oidc/v3/internal/testutil"
"github.com/zitadel/oidc/v3/pkg/oidc"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )

View file

@ -5,7 +5,7 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/oidc/v3/pkg/oidc/grants/tokenexchange" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc/grants/tokenexchange"
) )
// TokenExchangeRP extends the `RelyingParty` interface for the *draft* oauth2 `Token Exchange` // TokenExchangeRP extends the `RelyingParty` interface for the *draft* oauth2 `Token Exchange`

View file

@ -4,8 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type UserInfo struct { type UserInfo struct {

View file

@ -6,8 +6,8 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/zitadel/oidc/v3/pkg/client" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
// VerifyTokens implement the Token Response Validation as defined in OIDC specification // VerifyTokens implement the Token Response Validation as defined in OIDC specification

View file

@ -5,11 +5,11 @@ import (
"testing" "testing"
"time" "time"
tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
tu "github.com/zitadel/oidc/v3/internal/testutil"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
func TestVerifyTokens(t *testing.T) { func TestVerifyTokens(t *testing.T) {

View file

@ -4,9 +4,9 @@ import (
"context" "context"
"fmt" "fmt"
tu "github.com/zitadel/oidc/v3/internal/testutil" tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
"github.com/zitadel/oidc/v3/pkg/client/rp" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
// MyCustomClaims extends the TokenClaims base, // MyCustomClaims extends the TokenClaims base,

View file

@ -4,8 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/zitadel/oidc/v3/pkg/client/rs" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rs"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type IntrospectionResponse struct { type IntrospectionResponse struct {

View file

@ -6,9 +6,9 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/zitadel/oidc/v3/pkg/client" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type ResourceServer interface { type ResourceServer interface {

View file

@ -4,9 +4,9 @@ import (
"context" "context"
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
func TestNewResourceServer(t *testing.T) { func TestNewResourceServer(t *testing.T) {

View file

@ -6,10 +6,10 @@ import (
"net/http" "net/http"
"time" "time"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/client"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4"
"github.com/zitadel/oidc/v3/pkg/client"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
type TokenExchanger interface { type TokenExchanger interface {

View file

@ -10,7 +10,7 @@ import (
"github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
zcrypto "github.com/zitadel/oidc/v3/pkg/crypto" zcrypto "git.christmann.info/LARA/zitadel-oidc/v3/pkg/crypto"
) )
func TestBytesToPrivateKey(t *testing.T) { func TestBytesToPrivateKey(t *testing.T) {

View file

@ -11,7 +11,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
var DefaultHTTPClient = &http.Client{ var DefaultHTTPClient = &http.Client{

View file

@ -3,7 +3,7 @@ package oidc
import ( import (
"crypto/sha256" "crypto/sha256"
"github.com/zitadel/oidc/v3/pkg/crypto" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/crypto"
) )
const ( const (

View file

@ -145,6 +145,14 @@ type DiscoveryConfiguration struct {
// OPTermsOfServiceURI is a URL the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service. // OPTermsOfServiceURI is a URL the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service.
OPTermsOfServiceURI string `json:"op_tos_uri,omitempty"` OPTermsOfServiceURI string `json:"op_tos_uri,omitempty"`
// BackChannelLogoutSupported specifies whether the OP supports back-channel logout (https://openid.net/specs/openid-connect-backchannel-1_0.html),
// with true indicating support. If omitted, the default value is false.
BackChannelLogoutSupported bool `json:"backchannel_logout_supported,omitempty"`
// BackChannelLogoutSessionSupported specifies whether the OP can pass a sid (session ID) Claim in the Logout Token to identify the RP session with the OP.
// If supported, the sid Claim is also included in ID Tokens issued by the OP. If omitted, the default value is false.
BackChannelLogoutSessionSupported bool `json:"backchannel_logout_session_supported,omitempty"`
} }
type AuthMethod string type AuthMethod string

View file

@ -133,6 +133,7 @@ type Error struct {
ErrorType errorType `json:"error" schema:"error"` ErrorType errorType `json:"error" schema:"error"`
Description string `json:"error_description,omitempty" schema:"error_description,omitempty"` Description string `json:"error_description,omitempty" schema:"error_description,omitempty"`
State string `json:"state,omitempty" schema:"state,omitempty"` State string `json:"state,omitempty" schema:"state,omitempty"`
SessionState string `json:"session_state,omitempty" schema:"session_state,omitempty"`
redirectDisabled bool `schema:"-"` redirectDisabled bool `schema:"-"`
returnParent bool `schema:"-"` returnParent bool `schema:"-"`
} }
@ -142,11 +143,13 @@ func (e *Error) MarshalJSON() ([]byte, error) {
Error errorType `json:"error"` Error errorType `json:"error"`
ErrorDescription string `json:"error_description,omitempty"` ErrorDescription string `json:"error_description,omitempty"`
State string `json:"state,omitempty"` State string `json:"state,omitempty"`
SessionState string `json:"session_state,omitempty"`
Parent string `json:"parent,omitempty"` Parent string `json:"parent,omitempty"`
}{ }{
Error: e.ErrorType, Error: e.ErrorType,
ErrorDescription: e.Description, ErrorDescription: e.Description,
State: e.State, State: e.State,
SessionState: e.SessionState,
} }
if e.returnParent { if e.returnParent {
m.Parent = e.Parent.Error() m.Parent = e.Parent.Error()
@ -176,7 +179,8 @@ func (e *Error) Is(target error) bool {
} }
return e.ErrorType == t.ErrorType && return e.ErrorType == t.ErrorType &&
(e.Description == t.Description || t.Description == "") && (e.Description == t.Description || t.Description == "") &&
(e.State == t.State || t.State == "") (e.State == t.State || t.State == "") &&
(e.SessionState == t.SessionState || t.SessionState == "")
} }
func (e *Error) WithParent(err error) *Error { func (e *Error) WithParent(err error) *Error {
@ -242,6 +246,9 @@ func (e *Error) LogValue() slog.Value {
if e.State != "" { if e.State != "" {
attrs = append(attrs, slog.String("state", e.State)) attrs = append(attrs, slog.String("state", e.State))
} }
if e.SessionState != "" {
attrs = append(attrs, slog.String("session_state", e.SessionState))
}
if e.redirectDisabled { if e.redirectDisabled {
attrs = append(attrs, slog.Bool("redirect_disabled", e.redirectDisabled)) attrs = append(attrs, slog.Bool("redirect_disabled", e.redirectDisabled))
} }

View file

@ -4,7 +4,9 @@ package oidc
// https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout // https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
type EndSessionRequest struct { type EndSessionRequest struct {
IdTokenHint string `schema:"id_token_hint"` IdTokenHint string `schema:"id_token_hint"`
LogoutHint string `schema:"logout_hint"`
ClientID string `schema:"client_id"` ClientID string `schema:"client_id"`
PostLogoutRedirectURI string `schema:"post_logout_redirect_uri"` PostLogoutRedirectURI string `schema:"post_logout_redirect_uri"`
State string `schema:"state"` State string `schema:"state"`
UILocales Locales `schema:"ui_locales"`
} }

View file

@ -10,7 +10,7 @@ import (
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/zitadel/oidc/v3/pkg/crypto" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/crypto"
) )
const ( const (
@ -236,6 +236,7 @@ type AccessTokenResponse struct {
ExpiresIn uint64 `json:"expires_in,omitempty" schema:"expires_in,omitempty"` ExpiresIn uint64 `json:"expires_in,omitempty" schema:"expires_in,omitempty"`
IDToken string `json:"id_token,omitempty" schema:"id_token,omitempty"` IDToken string `json:"id_token,omitempty" schema:"id_token,omitempty"`
State string `json:"state,omitempty" schema:"state,omitempty"` State string `json:"state,omitempty" schema:"state,omitempty"`
Scope SpaceDelimitedArray `json:"scope,omitempty" schema:"scope,omitempty"`
} }
type JWTProfileAssertionClaims struct { type JWTProfileAssertionClaims struct {
@ -382,3 +383,40 @@ type TokenExchangeResponse struct {
// if the requested_token_type was Access Token and scope contained openid. // if the requested_token_type was Access Token and scope contained openid.
IDToken string `json:"id_token,omitempty"` IDToken string `json:"id_token,omitempty"`
} }
type LogoutTokenClaims struct {
Issuer string `json:"iss,omitempty"`
Subject string `json:"sub,omitempty"`
Audience Audience `json:"aud,omitempty"`
IssuedAt Time `json:"iat,omitempty"`
Expiration Time `json:"exp,omitempty"`
JWTID string `json:"jti,omitempty"`
Events map[string]any `json:"events,omitempty"`
SessionID string `json:"sid,omitempty"`
Claims map[string]any `json:"-"`
}
type ltcAlias LogoutTokenClaims
func (i *LogoutTokenClaims) MarshalJSON() ([]byte, error) {
return mergeAndMarshalClaims((*ltcAlias)(i), i.Claims)
}
func (i *LogoutTokenClaims) UnmarshalJSON(data []byte) error {
return unmarshalJSONMulti(data, (*ltcAlias)(i), &i.Claims)
}
func NewLogoutTokenClaims(issuer, subject string, audience Audience, expiration time.Time, jwtID, sessionID string, skew time.Duration) *LogoutTokenClaims {
return &LogoutTokenClaims{
Issuer: issuer,
Subject: subject,
Audience: audience,
IssuedAt: FromTime(time.Now().Add(-skew)),
Expiration: FromTime(expiration),
JWTID: jwtID,
Events: map[string]any{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
SessionID: sessionID,
}
}

View file

@ -242,3 +242,39 @@ func TestIDTokenClaims_GetUserInfo(t *testing.T) {
got := idTokenData.GetUserInfo() got := idTokenData.GetUserInfo()
assert.Equal(t, want, got) assert.Equal(t, want, got)
} }
func TestNewLogoutTokenClaims(t *testing.T) {
want := &LogoutTokenClaims{
Issuer: "zitadel",
Subject: "hello@me.com",
Audience: Audience{"foo", "just@me.com"},
Expiration: 12345,
JWTID: "jwtID",
Events: map[string]any{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
SessionID: "sessionID",
Claims: nil,
}
got := NewLogoutTokenClaims(
want.Issuer,
want.Subject,
want.Audience,
want.Expiration.AsTime(),
want.JWTID,
want.SessionID,
1*time.Second,
)
// test if the dynamic timestamp is around now,
// allowing for a delta of 1, just in case we flip on
// either side of a second boundry.
nowMinusSkew := NowTime() - 1
assert.InDelta(t, int64(nowMinusSkew), int64(got.IssuedAt), 1)
// Make equal not fail on dynamic timestamp
got.IssuedAt = 0
assert.Equal(t, want, got)
}

View file

@ -35,6 +35,17 @@ func (a *Audience) UnmarshalJSON(text []byte) error {
return nil return nil
} }
func (a *Audience) MarshalJSON() ([]byte, error) {
len := len(*a)
if len > 1 {
return json.Marshal(*a)
} else if len == 1 {
return json.Marshal((*a)[0])
}
return nil, errors.New("aud is empty")
}
type Display string type Display string
func (d *Display) UnmarshalText(text []byte) error { func (d *Display) UnmarshalText(text []byte) error {
@ -82,6 +93,9 @@ func (l *Locale) MarshalJSON() ([]byte, error) {
// to an empty value (language "und") and no error will be returned. // to an empty value (language "und") and no error will be returned.
// This state can be checked with the `l.Tag().IsRoot()` method. // This state can be checked with the `l.Tag().IsRoot()` method.
func (l *Locale) UnmarshalJSON(data []byte) error { func (l *Locale) UnmarshalJSON(data []byte) error {
if len(data) == 0 || string(data) == "\"\"" {
return nil
}
err := json.Unmarshal(data, &l.tag) err := json.Unmarshal(data, &l.tag)
if err == nil { if err == nil {
return nil return nil
@ -112,6 +126,14 @@ func ParseLocales(locales []string) Locales {
return out return out
} }
func (l Locales) String() string {
tags := make([]string, len(l))
for i, tag := range l {
tags[i] = tag.String()
}
return strings.Join(tags, " ")
}
// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
// It decodes an unquoted space seperated string into Locales. // It decodes an unquoted space seperated string into Locales.
// Undefined language tags in the input are ignored and ommited from // Undefined language tags in the input are ignored and ommited from
@ -228,6 +250,9 @@ func NewEncoder() *schema.Encoder {
e.RegisterEncoder(SpaceDelimitedArray{}, func(value reflect.Value) string { e.RegisterEncoder(SpaceDelimitedArray{}, func(value reflect.Value) string {
return value.Interface().(SpaceDelimitedArray).String() return value.Interface().(SpaceDelimitedArray).String()
}) })
e.RegisterEncoder(Locales{}, func(value reflect.Value) string {
return value.Interface().(Locales).String()
})
return e return e
} }

View file

@ -217,6 +217,30 @@ func TestLocale_UnmarshalJSON(t *testing.T) {
want dst want dst
wantErr bool wantErr bool
}{ }{
{
name: "value not present",
input: `{}`,
wantErr: false,
want: dst{
Locale: nil,
},
},
{
name: "null",
input: `{"locale": null}`,
wantErr: false,
want: dst{
Locale: nil,
},
},
{
name: "empty, ignored",
input: `{"locale": ""}`,
wantErr: false,
want: dst{
Locale: &Locale{},
},
},
{ {
name: "afrikaans, ok", name: "afrikaans, ok",
input: `{"locale": "af"}`, input: `{"locale": "af"}`,
@ -237,8 +261,8 @@ func TestLocale_UnmarshalJSON(t *testing.T) {
wantErr: true, wantErr: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var got dst var got dst
err := json.Unmarshal([]byte(tt.input), &got) err := json.Unmarshal([]byte(tt.input), &got)
if tt.wantErr { if tt.wantErr {
@ -247,6 +271,7 @@ func TestLocale_UnmarshalJSON(t *testing.T) {
} }
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tt.want, got) assert.Equal(t, tt.want, got)
})
} }
} }

View file

@ -7,12 +7,11 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"slices"
"strings" "strings"
"time" "time"
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
str "github.com/zitadel/oidc/v3/pkg/strings"
) )
type Claims interface { type Claims interface {
@ -84,7 +83,7 @@ type ACRVerifier func(string) error
// if none of the provided values matches the acr claim // if none of the provided values matches the acr claim
func DefaultACRVerifier(possibleValues []string) ACRVerifier { func DefaultACRVerifier(possibleValues []string) ACRVerifier {
return func(acr string) error { return func(acr string) error {
if !str.Contains(possibleValues, acr) { if !slices.Contains(possibleValues, acr) {
return fmt.Errorf("expected one of: %v, got: %q", possibleValues, acr) return fmt.Errorf("expected one of: %v, got: %q", possibleValues, acr)
} }
return nil return nil
@ -123,7 +122,7 @@ func CheckIssuer(claims Claims, issuer string) error {
} }
func CheckAudience(claims Claims, clientID string) error { func CheckAudience(claims Claims, clientID string) error {
if !str.Contains(claims.GetAudience(), clientID) { if !slices.Contains(claims.GetAudience(), clientID) {
return fmt.Errorf("%w: Audience must contain client_id %q", ErrAudience, clientID) return fmt.Errorf("%w: Audience must contain client_id %q", ErrAudience, clientID)
} }

View file

@ -5,10 +5,10 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
tu "github.com/zitadel/oidc/v3/internal/testutil"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
func TestParseToken(t *testing.T) { func TestParseToken(t *testing.T) {

View file

@ -15,10 +15,9 @@ import (
"strings" "strings"
"time" "time"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/bmatcuk/doublestar/v4" "github.com/bmatcuk/doublestar/v4"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
str "github.com/zitadel/oidc/v3/pkg/strings"
) )
type AuthRequest interface { type AuthRequest interface {
@ -39,6 +38,13 @@ type AuthRequest interface {
Done() bool Done() bool
} }
// AuthRequestSessionState should be implemented if [OpenID Connect Session Management](https://openid.net/specs/openid-connect-session-1_0.html) is supported
type AuthRequestSessionState interface {
// GetSessionState returns session_state.
// session_state is related to OpenID Connect Session Management.
GetSessionState() string
}
type Authorizer interface { type Authorizer interface {
Storage() Storage Storage() Storage
Decoder() httphelper.Decoder Decoder() httphelper.Decoder
@ -56,6 +62,12 @@ type AuthorizeValidator interface {
ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, *IDTokenHintVerifier) (string, error) ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, *IDTokenHintVerifier) (string, error)
} }
type CodeResponseType struct {
Code string `schema:"code"`
State string `schema:"state,omitempty"`
SessionState string `schema:"session_state,omitempty"`
}
func authorizeHandler(authorizer Authorizer) func(http.ResponseWriter, *http.Request) { func authorizeHandler(authorizer Authorizer) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
Authorize(w, r, authorizer) Authorize(w, r, authorizer)
@ -104,8 +116,8 @@ func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
} }
return ValidateAuthRequestClient(ctx, authReq, client, verifier) return ValidateAuthRequestClient(ctx, authReq, client, verifier)
} }
if validater, ok := authorizer.(AuthorizeValidator); ok { if validator, ok := authorizer.(AuthorizeValidator); ok {
validation = validater.ValidateAuthRequest validation = validator.ValidateAuthRequest
} }
userID, err := validation(ctx, authReq, authorizer.Storage(), authorizer.IDTokenHintVerifier(ctx)) userID, err := validation(ctx, authReq, authorizer.Storage(), authorizer.IDTokenHintVerifier(ctx))
if err != nil { if err != nil {
@ -156,7 +168,7 @@ func ParseRequestObject(ctx context.Context, authReq *oidc.AuthRequest, storage
if requestObject.Issuer != requestObject.ClientID { if requestObject.Issuer != requestObject.ClientID {
return oidc.ErrInvalidRequest().WithDescription("missing or wrong issuer in request") return oidc.ErrInvalidRequest().WithDescription("missing or wrong issuer in request")
} }
if !str.Contains(requestObject.Audience, issuer) { if !slices.Contains(requestObject.Audience, issuer) {
return oidc.ErrInvalidRequest().WithDescription("issuer missing in audience") return oidc.ErrInvalidRequest().WithDescription("issuer missing in audience")
} }
keySet := &jwtProfileKeySet{storage: storage, clientID: requestObject.Issuer} keySet := &jwtProfileKeySet{storage: storage, clientID: requestObject.Issuer}
@ -170,7 +182,7 @@ func ParseRequestObject(ctx context.Context, authReq *oidc.AuthRequest, storage
// CopyRequestObjectToAuthRequest overwrites present values from the Request Object into the auth request // CopyRequestObjectToAuthRequest overwrites present values from the Request Object into the auth request
// and clears the `RequestParam` of the auth request // and clears the `RequestParam` of the auth request
func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oidc.RequestObject) { func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oidc.RequestObject) {
if str.Contains(authReq.Scopes, oidc.ScopeOpenID) && len(requestObject.Scopes) > 0 { if slices.Contains(authReq.Scopes, oidc.ScopeOpenID) && len(requestObject.Scopes) > 0 {
authReq.Scopes = requestObject.Scopes authReq.Scopes = requestObject.Scopes
} }
if requestObject.RedirectURI != "" { if requestObject.RedirectURI != "" {
@ -288,7 +300,7 @@ func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
// checkURIAgainstRedirects just checks aginst the valid redirect URIs and ignores // checkURIAgainstRedirects just checks aginst the valid redirect URIs and ignores
// other factors. // other factors.
func checkURIAgainstRedirects(client Client, uri string) error { func checkURIAgainstRedirects(client Client, uri string) error {
if str.Contains(client.RedirectURIs(), uri) { if slices.Contains(client.RedirectURIs(), uri) {
return nil return nil
} }
if globClient, ok := client.(HasRedirectGlobs); ok { if globClient, ok := client.(HasRedirectGlobs); ok {
@ -313,12 +325,12 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
return oidc.ErrInvalidRequestRedirectURI().WithDescription("The redirect_uri is missing in the request. " + return oidc.ErrInvalidRequestRedirectURI().WithDescription("The redirect_uri is missing in the request. " +
"Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.") "Please ensure it is added to the request. If you have any questions, you may contact the administrator of the application.")
} }
if strings.HasPrefix(uri, "https://") {
return checkURIAgainstRedirects(client, uri)
}
if client.ApplicationType() == ApplicationTypeNative { if client.ApplicationType() == ApplicationTypeNative {
return validateAuthReqRedirectURINative(client, uri) return validateAuthReqRedirectURINative(client, uri)
} }
if strings.HasPrefix(uri, "https://") {
return checkURIAgainstRedirects(client, uri)
}
if err := checkURIAgainstRedirects(client, uri); err != nil { if err := checkURIAgainstRedirects(client, uri); err != nil {
return err return err
} }
@ -339,12 +351,15 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
// ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type // ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type
func validateAuthReqRedirectURINative(client Client, uri string) error { func validateAuthReqRedirectURINative(client Client, uri string) error {
parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri) parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
isCustomSchema := !strings.HasPrefix(uri, "http://") isCustomSchema := !(strings.HasPrefix(uri, "http://") || strings.HasPrefix(uri, "https://"))
if err := checkURIAgainstRedirects(client, uri); err == nil { if err := checkURIAgainstRedirects(client, uri); err == nil {
if client.DevMode() { if client.DevMode() {
return nil return nil
} }
// The RedirectURIs are only valid for native clients when localhost or non-"http://" if !isLoopback && strings.HasPrefix(uri, "https://") {
return nil
}
// The RedirectURIs are only valid for native clients when localhost or non-"http://" and "https://"
if isLoopback || isCustomSchema { if isLoopback || isCustomSchema {
return nil return nil
} }
@ -374,12 +389,12 @@ func HTTPLoopbackOrLocalhost(rawURL string) (*url.URL, bool) {
if err != nil { if err != nil {
return nil, false return nil, false
} }
if parsedURL.Scheme != "http" { if parsedURL.Scheme == "http" || parsedURL.Scheme == "https" {
return nil, false
}
hostName := parsedURL.Hostname() hostName := parsedURL.Hostname()
return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback() return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback()
} }
return nil, false
}
// ValidateAuthReqResponseType validates the passed response_type to the registered response types // ValidateAuthReqResponseType validates the passed response_type to the registered response types
func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType) error { func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType) error {
@ -468,41 +483,70 @@ func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWri
AuthResponseToken(w, r, authReq, authorizer, client) AuthResponseToken(w, r, authReq, authorizer, client)
} }
// AuthResponseCode creates the successful code authentication response // AuthResponseCode handles the creation of a successful authentication response using an authorization code
func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) { func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) {
ctx, span := tracer.Start(r.Context(), "AuthResponseCode") ctx, span := tracer.Start(r.Context(), "AuthResponseCode")
r = r.WithContext(ctx)
defer span.End() defer span.End()
r = r.WithContext(ctx)
var err error
if authReq.GetResponseMode() == oidc.ResponseModeFormPost {
err = handleFormPostResponse(w, r, authReq, authorizer)
} else {
err = handleRedirectResponse(w, r, authReq, authorizer)
}
code, err := CreateAuthRequestCode(r.Context(), authReq, authorizer.Storage(), authorizer.Crypto())
if err != nil { if err != nil {
AuthRequestError(w, r, authReq, err, authorizer) AuthRequestError(w, r, authReq, err, authorizer)
return
} }
codeResponse := struct { }
Code string `schema:"code"`
State string `schema:"state,omitempty"` // handleFormPostResponse processes the authentication response using form post method
}{ func handleFormPostResponse(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) error {
codeResponse, err := BuildAuthResponseCodeResponsePayload(r.Context(), authReq, authorizer)
if err != nil {
return err
}
return AuthResponseFormPost(w, authReq.GetRedirectURI(), codeResponse, authorizer.Encoder())
}
// handleRedirectResponse processes the authentication response using the redirect method
func handleRedirectResponse(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) error {
callbackURL, err := BuildAuthResponseCallbackURL(r.Context(), authReq, authorizer)
if err != nil {
return err
}
http.Redirect(w, r, callbackURL, http.StatusFound)
return nil
}
// BuildAuthResponseCodeResponsePayload generates the authorization code response payload for the authentication request
func BuildAuthResponseCodeResponsePayload(ctx context.Context, authReq AuthRequest, authorizer Authorizer) (*CodeResponseType, error) {
code, err := CreateAuthRequestCode(ctx, authReq, authorizer.Storage(), authorizer.Crypto())
if err != nil {
return nil, err
}
sessionState := ""
if authRequestSessionState, ok := authReq.(AuthRequestSessionState); ok {
sessionState = authRequestSessionState.GetSessionState()
}
return &CodeResponseType{
Code: code, Code: code,
State: authReq.GetState(), State: authReq.GetState(),
SessionState: sessionState,
}, nil
} }
if authReq.GetResponseMode() == oidc.ResponseModeFormPost { // BuildAuthResponseCallbackURL generates the callback URL for a successful authorization code response
err := AuthResponseFormPost(w, authReq.GetRedirectURI(), &codeResponse, authorizer.Encoder()) func BuildAuthResponseCallbackURL(ctx context.Context, authReq AuthRequest, authorizer Authorizer) (string, error) {
codeResponse, err := BuildAuthResponseCodeResponsePayload(ctx, authReq, authorizer)
if err != nil { if err != nil {
AuthRequestError(w, r, authReq, err, authorizer) return "", err
return
} }
return return AuthResponseURL(authReq.GetRedirectURI(), authReq.GetResponseType(), authReq.GetResponseMode(), codeResponse, authorizer.Encoder())
}
callback, err := AuthResponseURL(authReq.GetRedirectURI(), authReq.GetResponseType(), authReq.GetResponseMode(), &codeResponse, authorizer.Encoder())
if err != nil {
AuthRequestError(w, r, authReq, err, authorizer)
return
}
http.Redirect(w, r, callback, http.StatusFound)
} }
// AuthResponseToken creates the successful token(s) authentication response // AuthResponseToken creates the successful token(s) authentication response

View file

@ -11,15 +11,15 @@ import (
"reflect" "reflect"
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
tu "git.christmann.info/LARA/zitadel-oidc/v3/internal/testutil"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op/mock"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/example/server/storage"
tu "github.com/zitadel/oidc/v3/internal/testutil"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op/mock"
"github.com/zitadel/schema" "github.com/zitadel/schema"
) )
@ -433,6 +433,24 @@ func TestValidateAuthReqRedirectURI(t *testing.T) {
}, },
false, false,
}, },
{
"code flow registered https loopback v4 native ok",
args{
"https://127.0.0.1:4200/callback",
mock.NewClientWithConfig(t, []string{"https://127.0.0.1/callback"}, op.ApplicationTypeNative, nil, false),
oidc.ResponseTypeCode,
},
false,
},
{
"code flow registered https loopback v6 native ok",
args{
"https://[::1]:4200/callback",
mock.NewClientWithConfig(t, []string{"https://[::1]/callback"}, op.ApplicationTypeNative, nil, false),
oidc.ResponseTypeCode,
},
false,
},
{ {
"code flow unregistered http native fails", "code flow unregistered http native fails",
args{ args{
@ -1072,6 +1090,34 @@ func TestAuthResponseCode(t *testing.T) {
wantBody: "", wantBody: "",
}, },
}, },
{
name: "success with state and session_state",
args: args{
authReq: &storage.AuthRequestWithSessionState{
AuthRequest: &storage.AuthRequest{
ID: "id1",
TransferState: "state1",
},
SessionState: "session_state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantCode: http.StatusFound,
wantLocationHeader: "/auth/callback/?code=id1&session_state=session_state1&state=state1",
wantBody: "",
},
},
{ {
name: "success without state", // reproduce issue #415 name: "success without state", // reproduce issue #415
args: args{ args: args{
@ -1179,6 +1225,133 @@ func Test_parseAuthorizeCallbackRequest(t *testing.T) {
} }
} }
func TestBuildAuthResponseCodeResponsePayload(t *testing.T) {
type args struct {
authReq op.AuthRequest
authorizer func(*testing.T) op.Authorizer
}
type res struct {
wantCode string
wantState string
wantSessionState string
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "create code error",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{
returnErr: io.ErrClosedPipe,
})
return authorizer
},
},
res: res{
wantErr: true,
},
},
{
name: "success with state",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
TransferState: "state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
return authorizer
},
},
res: res{
wantCode: "id1",
wantState: "state1",
},
},
{
name: "success without state",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
TransferState: "",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
return authorizer
},
},
res: res{
wantCode: "id1",
wantState: "",
},
},
{
name: "success with session_state",
args: args{
authReq: &storage.AuthRequestWithSessionState{
AuthRequest: &storage.AuthRequest{
ID: "id1",
TransferState: "state1",
},
SessionState: "session_state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
return authorizer
},
},
res: res{
wantCode: "id1",
wantState: "state1",
wantSessionState: "session_state1",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := op.BuildAuthResponseCodeResponsePayload(context.Background(), tt.args.authReq, tt.args.authorizer(t))
if tt.res.wantErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.res.wantCode, got.Code)
assert.Equal(t, tt.res.wantState, got.State)
assert.Equal(t, tt.res.wantSessionState, got.SessionState)
})
}
}
func TestValidateAuthReqIDTokenHint(t *testing.T) { func TestValidateAuthReqIDTokenHint(t *testing.T) {
token, _ := tu.ValidIDToken() token, _ := tu.ValidIDToken()
tests := []struct { tests := []struct {
@ -1209,3 +1382,231 @@ func TestValidateAuthReqIDTokenHint(t *testing.T) {
}) })
} }
} }
func TestBuildAuthResponseCallbackURL(t *testing.T) {
type args struct {
authReq op.AuthRequest
authorizer func(*testing.T) op.Authorizer
}
type res struct {
wantURL string
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "error when generating code response",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{
returnErr: io.ErrClosedPipe,
})
return authorizer
},
},
res: res{
wantErr: true,
},
},
{
name: "error when generating callback URL",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
CallbackURI: "://invalid-url",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantErr: true,
},
},
{
name: "success with state",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
CallbackURI: "https://example.com/callback",
TransferState: "state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantURL: "https://example.com/callback?code=id1&state=state1",
wantErr: false,
},
},
{
name: "success without state",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
CallbackURI: "https://example.com/callback",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantURL: "https://example.com/callback?code=id1",
wantErr: false,
},
},
{
name: "success with session_state",
args: args{
authReq: &storage.AuthRequestWithSessionState{
AuthRequest: &storage.AuthRequest{
ID: "id1",
CallbackURI: "https://example.com/callback",
TransferState: "state1",
},
SessionState: "session_state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantURL: "https://example.com/callback?code=id1&session_state=session_state1&state=state1",
wantErr: false,
},
},
{
name: "success with existing query parameters",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
CallbackURI: "https://example.com/callback?param=value",
TransferState: "state1",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantURL: "https://example.com/callback?param=value&code=id1&state=state1",
wantErr: false,
},
},
{
name: "success with fragment response mode",
args: args{
authReq: &storage.AuthRequest{
ID: "id1",
CallbackURI: "https://example.com/callback",
TransferState: "state1",
ResponseMode: "fragment",
},
authorizer: func(t *testing.T) op.Authorizer {
ctrl := gomock.NewController(t)
storage := mock.NewMockStorage(ctrl)
storage.EXPECT().SaveAuthCode(gomock.Any(), "id1", "id1")
authorizer := mock.NewMockAuthorizer(ctrl)
authorizer.EXPECT().Storage().Return(storage)
authorizer.EXPECT().Crypto().Return(&mockCrypto{})
authorizer.EXPECT().Encoder().Return(schema.NewEncoder())
return authorizer
},
},
res: res{
wantURL: "https://example.com/callback#code=id1&state=state1",
wantErr: false,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := op.BuildAuthResponseCallbackURL(context.Background(), tt.args.authReq, tt.args.authorizer(t))
if tt.res.wantErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
if tt.res.wantURL != "" {
// Parse the URLs to compare components instead of direct string comparison
expectedURL, err := url.Parse(tt.res.wantURL)
require.NoError(t, err)
actualURL, err := url.Parse(got)
require.NoError(t, err)
// Compare the base parts (scheme, host, path)
assert.Equal(t, expectedURL.Scheme, actualURL.Scheme)
assert.Equal(t, expectedURL.Host, actualURL.Host)
assert.Equal(t, expectedURL.Path, actualURL.Path)
// Compare the fragment if any
assert.Equal(t, expectedURL.Fragment, actualURL.Fragment)
// For query parameters, compare them independently of order
expectedQuery := expectedURL.Query()
actualQuery := actualURL.Query()
assert.Equal(t, len(expectedQuery), len(actualQuery), "Query parameter count does not match")
for key, expectedValues := range expectedQuery {
actualValues, exists := actualQuery[key]
assert.True(t, exists, "Expected query parameter %s not found", key)
assert.ElementsMatch(t, expectedValues, actualValues, "Values for parameter %s don't match", key)
}
}
})
}
}

View file

@ -7,8 +7,8 @@ import (
"net/url" "net/url"
"time" "time"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
//go:generate go get github.com/dmarkham/enumer //go:generate go get github.com/dmarkham/enumer

View file

@ -10,13 +10,13 @@ import (
"strings" "strings"
"testing" "testing"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op/mock"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op/mock"
"github.com/zitadel/schema" "github.com/zitadel/schema"
) )

View file

@ -30,6 +30,7 @@ type Configuration interface {
EndSessionEndpoint() *Endpoint EndSessionEndpoint() *Endpoint
KeysEndpoint() *Endpoint KeysEndpoint() *Endpoint
DeviceAuthorizationEndpoint() *Endpoint DeviceAuthorizationEndpoint() *Endpoint
CheckSessionIframe() *Endpoint
AuthMethodPostSupported() bool AuthMethodPostSupported() bool
CodeMethodS256Supported() bool CodeMethodS256Supported() bool
@ -49,6 +50,9 @@ type Configuration interface {
SupportedUILocales() []language.Tag SupportedUILocales() []language.Tag
DeviceAuthorization() DeviceAuthorizationConfig DeviceAuthorization() DeviceAuthorizationConfig
BackChannelLogoutSupported() bool
BackChannelLogoutSessionSupported() bool
} }
type IssuerFromRequest func(r *http.Request) string type IssuerFromRequest func(r *http.Request) string

View file

@ -1,7 +1,7 @@
package op package op
import ( import (
"github.com/zitadel/oidc/v3/pkg/crypto" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/crypto"
) )
type Crypto interface { type Crypto interface {

View file

@ -9,12 +9,12 @@ import (
"math/big" "math/big"
"net/http" "net/http"
"net/url" "net/url"
"slices"
"strings" "strings"
"time" "time"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
strs "github.com/zitadel/oidc/v3/pkg/strings"
) )
type DeviceAuthorizationConfig struct { type DeviceAuthorizationConfig struct {
@ -91,10 +91,7 @@ func createDeviceAuthorization(ctx context.Context, req *oidc.DeviceAuthorizatio
} }
config := o.DeviceAuthorization() config := o.DeviceAuthorization()
deviceCode, err := NewDeviceCode(RecommendedDeviceCodeBytes) deviceCode, _ := NewDeviceCode(RecommendedDeviceCodeBytes)
if err != nil {
return nil, NewStatusError(err, http.StatusInternalServerError)
}
userCode, err := NewUserCode([]rune(config.UserCode.CharSet), config.UserCode.CharAmount, config.UserCode.DashInterval) userCode, err := NewUserCode([]rune(config.UserCode.CharSet), config.UserCode.CharAmount, config.UserCode.DashInterval)
if err != nil { if err != nil {
return nil, NewStatusError(err, http.StatusInternalServerError) return nil, NewStatusError(err, http.StatusInternalServerError)
@ -163,11 +160,14 @@ func ParseDeviceCodeRequest(r *http.Request, o OpenIDProvider) (*oidc.DeviceAuth
// results in a 22 character base64 encoded string. // results in a 22 character base64 encoded string.
const RecommendedDeviceCodeBytes = 16 const RecommendedDeviceCodeBytes = 16
// NewDeviceCode generates a new cryptographically secure device code as a base64 encoded string.
// The length of the string is nBytes * 4 / 3.
// An error is never returned.
//
// TODO(v4): change return type to string alone.
func NewDeviceCode(nBytes int) (string, error) { func NewDeviceCode(nBytes int) (string, error) {
bytes := make([]byte, nBytes) bytes := make([]byte, nBytes)
if _, err := rand.Read(bytes); err != nil { rand.Read(bytes)
return "", fmt.Errorf("%w getting entropy for device code", err)
}
return base64.RawURLEncoding.EncodeToString(bytes), nil return base64.RawURLEncoding.EncodeToString(bytes), nil
} }
@ -276,7 +276,7 @@ func (r *DeviceAuthorizationState) GetAMR() []string {
} }
func (r *DeviceAuthorizationState) GetAudience() []string { func (r *DeviceAuthorizationState) GetAudience() []string {
if !strs.Contains(r.Audience, r.ClientID) { if !slices.Contains(r.Audience, r.ClientID) {
r.Audience = append(r.Audience, r.ClientID) r.Audience = append(r.Audience, r.ClientID)
} }
return r.Audience return r.Audience
@ -344,10 +344,11 @@ func CreateDeviceTokenResponse(ctx context.Context, tokenRequest TokenRequest, c
RefreshToken: refreshToken, RefreshToken: refreshToken,
TokenType: oidc.BearerToken, TokenType: oidc.BearerToken,
ExpiresIn: uint64(validity.Seconds()), ExpiresIn: uint64(validity.Seconds()),
Scope: tokenRequest.GetScopes(),
} }
// TODO(v4): remove type assertion // TODO(v4): remove type assertion
if idTokenRequest, ok := tokenRequest.(IDTokenRequest); ok && strs.Contains(tokenRequest.GetScopes(), oidc.ScopeOpenID) { if idTokenRequest, ok := tokenRequest.(IDTokenRequest); ok && slices.Contains(tokenRequest.GetScopes(), oidc.ScopeOpenID) {
response.IDToken, err = CreateIDToken(ctx, IssuerFromContext(ctx), idTokenRequest, client.IDTokenLifetime(), accessToken, "", creator.Storage(), client) response.IDToken, err = CreateIDToken(ctx, IssuerFromContext(ctx), idTokenRequest, client.IDTokenLifetime(), accessToken, "", creator.Storage(), client)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -13,12 +13,12 @@ import (
"testing" "testing"
"time" "time"
"git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/example/server/storage"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
) )
func Test_deviceAuthorizationHandler(t *testing.T) { func Test_deviceAuthorizationHandler(t *testing.T) {
@ -145,21 +145,11 @@ func runWithRandReader(r io.Reader, f func()) {
} }
func TestNewDeviceCode(t *testing.T) { func TestNewDeviceCode(t *testing.T) {
t.Run("reader error", func(t *testing.T) {
runWithRandReader(errReader{}, func() {
_, err := op.NewDeviceCode(16)
require.Error(t, err)
})
})
t.Run("different lengths, rand reader", func(t *testing.T) {
for i := 1; i <= 32; i++ { for i := 1; i <= 32; i++ {
got, err := op.NewDeviceCode(i) got, err := op.NewDeviceCode(i)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, got, base64.RawURLEncoding.EncodedLen(i)) assert.Len(t, got, base64.RawURLEncoding.EncodedLen(i))
} }
})
} }
func TestNewUserCode(t *testing.T) { func TestNewUserCode(t *testing.T) {

View file

@ -6,8 +6,8 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type DiscoverStorage interface { type DiscoverStorage interface {
@ -45,6 +45,7 @@ func CreateDiscoveryConfig(ctx context.Context, config Configuration, storage Di
EndSessionEndpoint: config.EndSessionEndpoint().Absolute(issuer), EndSessionEndpoint: config.EndSessionEndpoint().Absolute(issuer),
JwksURI: config.KeysEndpoint().Absolute(issuer), JwksURI: config.KeysEndpoint().Absolute(issuer),
DeviceAuthorizationEndpoint: config.DeviceAuthorizationEndpoint().Absolute(issuer), DeviceAuthorizationEndpoint: config.DeviceAuthorizationEndpoint().Absolute(issuer),
CheckSessionIframe: config.CheckSessionIframe().Absolute(issuer),
ScopesSupported: Scopes(config), ScopesSupported: Scopes(config),
ResponseTypesSupported: ResponseTypes(config), ResponseTypesSupported: ResponseTypes(config),
GrantTypesSupported: GrantTypes(config), GrantTypesSupported: GrantTypes(config),
@ -61,6 +62,8 @@ func CreateDiscoveryConfig(ctx context.Context, config Configuration, storage Di
CodeChallengeMethodsSupported: CodeChallengeMethods(config), CodeChallengeMethodsSupported: CodeChallengeMethods(config),
UILocalesSupported: config.SupportedUILocales(), UILocalesSupported: config.SupportedUILocales(),
RequestParameterSupported: config.RequestObjectSupported(), RequestParameterSupported: config.RequestObjectSupported(),
BackChannelLogoutSupported: config.BackChannelLogoutSupported(),
BackChannelLogoutSessionSupported: config.BackChannelLogoutSessionSupported(),
} }
} }
@ -92,11 +95,17 @@ func createDiscoveryConfigV2(ctx context.Context, config Configuration, storage
CodeChallengeMethodsSupported: CodeChallengeMethods(config), CodeChallengeMethodsSupported: CodeChallengeMethods(config),
UILocalesSupported: config.SupportedUILocales(), UILocalesSupported: config.SupportedUILocales(),
RequestParameterSupported: config.RequestObjectSupported(), RequestParameterSupported: config.RequestObjectSupported(),
BackChannelLogoutSupported: config.BackChannelLogoutSupported(),
BackChannelLogoutSessionSupported: config.BackChannelLogoutSessionSupported(),
} }
} }
func Scopes(c Configuration) []string { func Scopes(c Configuration) []string {
return DefaultSupportedScopes // TODO: config provider, ok := c.(*Provider)
if ok && provider.config.SupportedScopes != nil {
return provider.config.SupportedScopes
}
return DefaultSupportedScopes
} }
func ResponseTypes(c Configuration) []string { func ResponseTypes(c Configuration) []string {

View file

@ -11,9 +11,9 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op/mock" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op/mock"
) )
func TestDiscover(t *testing.T) { func TestDiscover(t *testing.T) {
@ -81,6 +81,11 @@ func Test_scopes(t *testing.T) {
args{}, args{},
op.DefaultSupportedScopes, op.DefaultSupportedScopes,
}, },
{
"custom scopes",
args{newTestProvider(&op.Config{SupportedScopes: []string{"test1", "test2"}})},
[]string{"test1", "test2"},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -3,8 +3,8 @@ package op_test
import ( import (
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/op"
) )
func TestEndpoint_Path(t *testing.T) { func TestEndpoint_Path(t *testing.T) {

View file

@ -7,8 +7,8 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
type ErrAuthRequest interface { type ErrAuthRequest interface {
@ -46,6 +46,12 @@ func AuthRequestError(w http.ResponseWriter, r *http.Request, authReq ErrAuthReq
return return
} }
e.State = authReq.GetState() e.State = authReq.GetState()
var sessionState string
authRequestSessionState, ok := authReq.(AuthRequestSessionState)
if ok {
sessionState = authRequestSessionState.GetSessionState()
}
e.SessionState = sessionState
var responseMode oidc.ResponseMode var responseMode oidc.ResponseMode
if rm, ok := authReq.(interface{ GetResponseMode() oidc.ResponseMode }); ok { if rm, ok := authReq.(interface{ GetResponseMode() oidc.ResponseMode }); ok {
responseMode = rm.GetResponseMode() responseMode = rm.GetResponseMode()
@ -92,6 +98,12 @@ func TryErrorRedirect(ctx context.Context, authReq ErrAuthRequest, parent error,
} }
e.State = authReq.GetState() e.State = authReq.GetState()
var sessionState string
authRequestSessionState, ok := authReq.(AuthRequestSessionState)
if ok {
sessionState = authRequestSessionState.GetSessionState()
}
e.SessionState = sessionState
var responseMode oidc.ResponseMode var responseMode oidc.ResponseMode
if rm, ok := authReq.(interface{ GetResponseMode() oidc.ResponseMode }); ok { if rm, ok := authReq.(interface{ GetResponseMode() oidc.ResponseMode }); ok {
responseMode = rm.GetResponseMode() responseMode = rm.GetResponseMode()

View file

@ -11,9 +11,9 @@ import (
"strings" "strings"
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/schema" "github.com/zitadel/schema"
) )

View file

@ -6,7 +6,7 @@ import (
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
) )
type KeyProvider interface { type KeyProvider interface {

View file

@ -11,9 +11,9 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op/mock" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op/mock"
) )
func TestKeys(t *testing.T) { func TestKeys(t *testing.T) {

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: Authorizer) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: Authorizer)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -9,9 +9,9 @@ import (
slog "log/slog" slog "log/slog"
reflect "reflect" reflect "reflect"
http "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
http "github.com/zitadel/oidc/v3/pkg/http"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
// MockAuthorizer is a mock of Authorizer interface. // MockAuthorizer is a mock of Authorizer interface.

View file

@ -8,8 +8,8 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/zitadel/schema" "github.com/zitadel/schema"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
func NewAuthorizer(t *testing.T) op.Authorizer { func NewAuthorizer(t *testing.T) op.Authorizer {

View file

@ -5,8 +5,8 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
func NewClient(t *testing.T) op.Client { func NewClient(t *testing.T) op.Client {

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: Client) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: Client)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -8,9 +8,9 @@ import (
reflect "reflect" reflect "reflect"
time "time" time "time"
oidc "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
oidc "github.com/zitadel/oidc/v3/pkg/oidc"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
// MockClient is a mock of Client interface. // MockClient is a mock of Client interface.

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: Configuration) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: Configuration)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -8,8 +8,8 @@ import (
http "net/http" http "net/http"
reflect "reflect" reflect "reflect"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
op "github.com/zitadel/oidc/v3/pkg/op"
language "golang.org/x/text/language" language "golang.org/x/text/language"
) )
@ -78,6 +78,48 @@ func (mr *MockConfigurationMockRecorder) AuthorizationEndpoint() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizationEndpoint", reflect.TypeOf((*MockConfiguration)(nil).AuthorizationEndpoint)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizationEndpoint", reflect.TypeOf((*MockConfiguration)(nil).AuthorizationEndpoint))
} }
// BackChannelLogoutSessionSupported mocks base method.
func (m *MockConfiguration) BackChannelLogoutSessionSupported() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BackChannelLogoutSessionSupported")
ret0, _ := ret[0].(bool)
return ret0
}
// BackChannelLogoutSessionSupported indicates an expected call of BackChannelLogoutSessionSupported.
func (mr *MockConfigurationMockRecorder) BackChannelLogoutSessionSupported() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BackChannelLogoutSessionSupported", reflect.TypeOf((*MockConfiguration)(nil).BackChannelLogoutSessionSupported))
}
// BackChannelLogoutSupported mocks base method.
func (m *MockConfiguration) BackChannelLogoutSupported() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BackChannelLogoutSupported")
ret0, _ := ret[0].(bool)
return ret0
}
// BackChannelLogoutSupported indicates an expected call of BackChannelLogoutSupported.
func (mr *MockConfigurationMockRecorder) BackChannelLogoutSupported() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BackChannelLogoutSupported", reflect.TypeOf((*MockConfiguration)(nil).BackChannelLogoutSupported))
}
// CheckSessionIframe mocks base method.
func (m *MockConfiguration) CheckSessionIframe() *op.Endpoint {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CheckSessionIframe")
ret0, _ := ret[0].(*op.Endpoint)
return ret0
}
// CheckSessionIframe indicates an expected call of CheckSessionIframe.
func (mr *MockConfigurationMockRecorder) CheckSessionIframe() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckSessionIframe", reflect.TypeOf((*MockConfiguration)(nil).CheckSessionIframe))
}
// CodeMethodS256Supported mocks base method. // CodeMethodS256Supported mocks base method.
func (m *MockConfiguration) CodeMethodS256Supported() bool { func (m *MockConfiguration) CodeMethodS256Supported() bool {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: DiscoverStorage) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: DiscoverStorage)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View file

@ -1,11 +1,11 @@
package mock package mock
//go:generate go install github.com/golang/mock/mockgen@v1.6.0 //go:generate go install github.com/golang/mock/mockgen@v1.6.0
//go:generate mockgen -package mock -destination ./storage.mock.go github.com/zitadel/oidc/v3/pkg/op Storage //go:generate mockgen -package mock -destination ./storage.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op Storage
//go:generate mockgen -package mock -destination ./authorizer.mock.go github.com/zitadel/oidc/v3/pkg/op Authorizer //go:generate mockgen -package mock -destination ./authorizer.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op Authorizer
//go:generate mockgen -package mock -destination ./client.mock.go github.com/zitadel/oidc/v3/pkg/op Client //go:generate mockgen -package mock -destination ./client.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op Client
//go:generate mockgen -package mock -destination ./glob.mock.go github.com/zitadel/oidc/v3/pkg/op HasRedirectGlobs //go:generate mockgen -package mock -destination ./glob.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op HasRedirectGlobs
//go:generate mockgen -package mock -destination ./configuration.mock.go github.com/zitadel/oidc/v3/pkg/op Configuration //go:generate mockgen -package mock -destination ./configuration.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op Configuration
//go:generate mockgen -package mock -destination ./discovery.mock.go github.com/zitadel/oidc/v3/pkg/op DiscoverStorage //go:generate mockgen -package mock -destination ./discovery.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op DiscoverStorage
//go:generate mockgen -package mock -destination ./signer.mock.go github.com/zitadel/oidc/v3/pkg/op SigningKey,Key //go:generate mockgen -package mock -destination ./signer.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op SigningKey,Key
//go:generate mockgen -package mock -destination ./key.mock.go github.com/zitadel/oidc/v3/pkg/op KeyProvider //go:generate mockgen -package mock -destination ./key.mock.go git.christmann.info/LARA/zitadel-oidc/v3/pkg/op KeyProvider

View file

@ -3,9 +3,9 @@ package mock
import ( import (
"testing" "testing"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
"github.com/zitadel/oidc/v3/pkg/oidc"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
func NewHasRedirectGlobs(t *testing.T) op.HasRedirectGlobs { func NewHasRedirectGlobs(t *testing.T) op.HasRedirectGlobs {

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: HasRedirectGlobs) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: HasRedirectGlobs)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -8,9 +8,9 @@ import (
reflect "reflect" reflect "reflect"
time "time" time "time"
oidc "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
oidc "github.com/zitadel/oidc/v3/pkg/oidc"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
// MockHasRedirectGlobs is a mock of HasRedirectGlobs interface. // MockHasRedirectGlobs is a mock of HasRedirectGlobs interface.

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: KeyProvider) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: KeyProvider)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -8,8 +8,8 @@ import (
context "context" context "context"
reflect "reflect" reflect "reflect"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
// MockKeyProvider is a mock of KeyProvider interface. // MockKeyProvider is a mock of KeyProvider interface.

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: SigningKey,Key) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: SigningKey,Key)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/oidc/v3/pkg/op (interfaces: Storage) // Source: git.christmann.info/LARA/zitadel-oidc/v3/pkg/op (interfaces: Storage)
// Package mock is a generated GoMock package. // Package mock is a generated GoMock package.
package mock package mock
@ -9,10 +9,10 @@ import (
reflect "reflect" reflect "reflect"
time "time" time "time"
oidc "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
op "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
jose "github.com/go-jose/go-jose/v4" jose "github.com/go-jose/go-jose/v4"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
oidc "github.com/zitadel/oidc/v3/pkg/oidc"
op "github.com/zitadel/oidc/v3/pkg/op"
) )
// MockStorage is a mock of Storage interface. // MockStorage is a mock of Storage interface.

View file

@ -8,8 +8,8 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
) )
func NewStorage(t *testing.T) op.Storage { func NewStorage(t *testing.T) op.Storage {

View file

@ -14,8 +14,8 @@ import (
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"golang.org/x/text/language" "golang.org/x/text/language"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc" "git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
) )
const ( const (
@ -167,7 +167,10 @@ type Config struct {
RequestObjectSupported bool RequestObjectSupported bool
SupportedUILocales []language.Tag SupportedUILocales []language.Tag
SupportedClaims []string SupportedClaims []string
SupportedScopes []string
DeviceAuthorization DeviceAuthorizationConfig DeviceAuthorization DeviceAuthorizationConfig
BackChannelLogoutSupported bool
BackChannelLogoutSessionSupported bool
} }
// Endpoints defines endpoint routes. // Endpoints defines endpoint routes.
@ -336,6 +339,10 @@ func (o *Provider) DeviceAuthorizationEndpoint() *Endpoint {
return o.endpoints.DeviceAuthorization return o.endpoints.DeviceAuthorization
} }
func (o *Provider) CheckSessionIframe() *Endpoint {
return o.endpoints.CheckSessionIframe
}
func (o *Provider) KeysEndpoint() *Endpoint { func (o *Provider) KeysEndpoint() *Endpoint {
return o.endpoints.JwksURI return o.endpoints.JwksURI
} }
@ -411,6 +418,14 @@ func (o *Provider) DeviceAuthorization() DeviceAuthorizationConfig {
return o.config.DeviceAuthorization return o.config.DeviceAuthorization
} }
func (o *Provider) BackChannelLogoutSupported() bool {
return o.config.BackChannelLogoutSupported
}
func (o *Provider) BackChannelLogoutSessionSupported() bool {
return o.config.BackChannelLogoutSessionSupported
}
func (o *Provider) Storage() Storage { func (o *Provider) Storage() Storage {
return o.storage return o.storage
} }

View file

@ -11,12 +11,12 @@ import (
"testing" "testing"
"time" "time"
"git.christmann.info/LARA/zitadel-oidc/v3/example/server/storage"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/op"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/example/server/storage"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
"golang.org/x/text/language" "golang.org/x/text/language"
) )
@ -232,7 +232,7 @@ func TestRoutes(t *testing.T) {
"scope": oidc.SpaceDelimitedArray{oidc.ScopeOpenID, oidc.ScopeOfflineAccess}.String(), "scope": oidc.SpaceDelimitedArray{oidc.ScopeOpenID, oidc.ScopeOfflineAccess}.String(),
}, },
wantCode: http.StatusOK, wantCode: http.StatusOK,
contains: []string{`{"access_token":"`, `","token_type":"Bearer","expires_in":299}`}, contains: []string{`{"access_token":"`, `","token_type":"Bearer","expires_in":299,"scope":"openid offline_access"}`},
}, },
{ {
// This call will fail. A successful test is already // This call will fail. A successful test is already

View file

@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
httphelper "github.com/zitadel/oidc/v3/pkg/http" httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
) )
type ProbesFn func(context.Context) error type ProbesFn func(context.Context) error

View file

@ -5,9 +5,9 @@ import (
"net/http" "net/http"
"net/url" "net/url"
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/oidc"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
) )
// Server describes the interface that needs to be implemented to serve // Server describes the interface that needs to be implemented to serve

Some files were not shown because too many files have changed in this diff Show more