fix(oidc): use authenticated encryption for opaque tokens (#12017)

# Which Problems Are Solved

Opaque tokens now use authenticated encryption.

# How the Problems Are Solved

- Upgrade zitadel/oidc to v3.47
- Copy crypto implementation for refresh and session tokens (internal to
zitadel)
- Added config that allows validating old tokens for gradual roll-out

# Additional Changes

- Set NX cache for `integration-test-build` to `false`, working on a
seperate fix.

# Additional Context

- closes #11315

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
This commit is contained in:
Tim Möhlmann
2026-04-13 10:59:50 +00:00
committed by GitHub
co-authored by copilot-swe-agent[bot] <198982749+[email protected]> muhlemmer
parent a28ee63b02
commit 01fe34a526
46 changed files with 406 additions and 201 deletions
+11
View File
@@ -774,6 +774,17 @@ EncryptionKeys:
EncryptionKeyID: "idpConfigKey" # ZITADEL_ENCRYPTIONKEYS_IDPCONFIG_ENCRYPTIONKEYID
DecryptionKeyIDs: # ZITADEL_ENCRYPTIONKEYS_IDPCONFIG_DECRYPTIONKEYIDS (comma separated list)
OIDC:
# Accept opaque tokens (access, session, refresh tokens, PATs etc) created by older ZITADEL versions.
# Legacy tokens are vulnerable to certain crypto attacks,
# so this should only be enabled during a migration and disabled afterwards.
# After upgrading ZITADEL, new values will use authenticated encryption.
# When this option is enabled tokens emitted from before the upgrade will still be accepted until they expire,
# allowing gradual rollout of new tokens.
# This allows upgrading ZITADEL without forcing logout of all users (and invalidating all PATs)
# This option should be disabled as soon as all tokens have been replaced and PATs rotated.
# Note: older versions of ZITADEL aren't able to verify newer tokens.
# Downgrading ZITADEL will always logout all users that obtained a token after the upgrade.
LegacyToken: true # ZITADEL_ENCRYPTIONKEYS_OIDC_LEGACYTOKEN
EncryptionKeyID: "oidcKey" # ZITADEL_ENCRYPTIONKEYS_OIDC_ENCRYPTIONKEYID
DecryptionKeyIDs: # ZITADEL_ENCRYPTIONKEYS_OIDC_DECRYPTIONKEYIDS (comma separated list)
SAML:
+1 -1
View File
@@ -40,7 +40,7 @@ type EncryptionKeyConfig struct {
type EncryptionKeys struct {
DomainVerification crypto.EncryptionAlgorithm
IDPConfig crypto.EncryptionAlgorithm
OIDC crypto.EncryptionAlgorithm
OIDC crypto.AuthEncryptionAlgorithm
SAML crypto.EncryptionAlgorithm
OTP crypto.EncryptionAlgorithm
SMS crypto.EncryptionAlgorithm
+1 -1
View File
@@ -203,9 +203,9 @@ func projections(
keys.SMS,
keys.User,
keys.DomainVerification,
keys.OIDC,
keys.SAML,
keys.Target,
keys.OIDC,
&http.Client{},
func(ctx context.Context, permission, orgID, resourceID string) (err error) {
return internal_authz.CheckPermission(ctx, authZRepo, config.SystemAuthZ.RolePermissionMappings, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
+2 -2
View File
@@ -86,12 +86,12 @@ func (mig *FirstInstance) Execute(ctx context.Context, _ eventstore.Event) error
nil,
userAlg,
nil,
nil,
nil,
oidcEncryption,
nil,
nil,
nil,
nil,
nil,
0,
0,
0,
+1 -1
View File
@@ -565,9 +565,9 @@ func startCommandsQueries(
keys.SMS,
keys.User,
keys.DomainVerification,
keys.OIDC,
keys.SAML,
keys.Target,
keys.OIDC,
&http.Client{},
permissionCheck,
sessionTokenVerifier,
+1 -1
View File
@@ -288,9 +288,9 @@ func startZitadel(ctx context.Context, config *Config, masterKey string, server
keys.SMS,
keys.User,
keys.DomainVerification,
keys.OIDC,
keys.SAML,
keys.Target,
keys.OIDC,
&http.Client{},
permissionCheck,
sessionTokenVerifier,