Merge commit from fork

* feat(jwt idp): manage and validate audience

* translations

* fix tests

* address comments

* update migration version

* fix merge
This commit is contained in:
Livio Spring
2026-06-15 15:27:47 +02:00
committed by GitHub
parent fad02c6d9f
commit d184e976fc
57 changed files with 379 additions and 55 deletions
@@ -61,6 +61,15 @@ the format specified in [RFC7517](https://datatracker.ietf.org/doc/html/rfc7517)
*Example: `https://issuer.test.internal/keys`*
### Audience (optional)
The expected audience (`aud` claim) in the JWT. If set, ZITADEL will validate that the JWT contains this audience.
It's recommended to set this to ensure the JWT is intended to be used by ZITADEL.
If the JWT contains multiple audiences, the configured audience must be one of them.
If no audience is configured, ZITADEL will not validate the `aud` claim.
*Example: `my-client`*
### JWT endpoint
Where ZITADEL redirects users to retrieve the JWT.
@@ -145,7 +154,7 @@ You have an existing application which exists in an internal network which handl
application is built using ZITADEL but the userbase of the existing application needs to be able to open the new
application from within the existing one without creating a new account or having to sign in.
- Existing application: `apps.test.com/existing/`
- Existing application: `apps.test.com/existing/` (also used as audience)
- Existing internal auth service: `issuer.test.internal`
- New application: `new.test.com`
- ZITADEL Login UI: `accounts.test.com`
@@ -163,6 +172,7 @@ application from within the existing one without creating a new account or havin
- Keys endpoint: `issuer.test.internal/keys`
- Header name: `x-custom-tkn`
- Issuer: `issuer.test.internal`
- Audience: `apps.test.com/existing/`
#### Result flow
+1
View File
@@ -97,6 +97,7 @@ type JWT struct {
Issuer string `json:"issuer,omitempty"`
KeysEndpoint string `json:"keysEndpoint,omitempty"`
HeaderName string `json:"headerName,omitempty"`
Audience string `json:"audience,omitempty"`
}
type IDPJWT struct {
+27
View File
@@ -0,0 +1,27 @@
package setup
import (
"context"
_ "embed"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/eventstore"
)
var (
//go:embed 71.sql
addJWTAudience string
)
type JWTProvideAddAudienceColumn struct {
dbClient *database.DB
}
func (mig *JWTProvideAddAudienceColumn) Execute(ctx context.Context, _ eventstore.Event) error {
_, err := mig.dbClient.ExecContext(ctx, addJWTAudience)
return err
}
func (mig *JWTProvideAddAudienceColumn) String() string {
return "71_idp_templates6_jwt_add_audience"
}
+2
View File
@@ -0,0 +1,2 @@
ALTER TABLE IF EXISTS projections.idp_templates6_jwt
ADD COLUMN IF NOT EXISTS audience text;
+1
View File
@@ -186,6 +186,7 @@ type Steps struct {
s68TargetAddPayloadTypeColumn *TargetAddPayloadTypeColumn
s69CacheTablesLogged *CacheTablesLogged
s70AddEventStoreCommandEnforceOwner *AddEventStoreCommandEnforceOwnerColumn
s71JWTProvideAddAudienceColumn *JWTProvideAddAudienceColumn
RelationalTables *TransactionalTables
}
+2
View File
@@ -249,6 +249,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s68TargetAddPayloadTypeColumn = &TargetAddPayloadTypeColumn{dbClient: dbClient}
steps.s69CacheTablesLogged = &CacheTablesLogged{dbClient: dbClient}
steps.s70AddEventStoreCommandEnforceOwner = &AddEventStoreCommandEnforceOwnerColumn{dbClient: dbClient}
steps.s71JWTProvideAddAudienceColumn = &JWTProvideAddAudienceColumn{dbClient: dbClient}
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
if err != nil {
@@ -372,6 +373,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s59SetupWebkeys, // this step needs commands.
steps.s66SessionRecoveryCodeCheckedAt,
steps.s68TargetAddPayloadTypeColumn,
steps.s71JWTProvideAddAudienceColumn,
} {
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
if setupErr != nil {
@@ -56,6 +56,10 @@
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
<input cnslInput formControlName="keysEndpoint" />
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.JWT.AUDIENCE' | translate }}</cnsl-label>
<input cnslInput formControlName="audience" placeholder="my-client" />
</cnsl-form-field>
</div>
<div class="identity-provider-optional-h-wrapper">
@@ -117,6 +117,7 @@ export class ProviderJWTComponent {
issuer: new UntypedFormControl('', [requiredValidator]),
jwtEndpoint: new UntypedFormControl('', [requiredValidator]),
keysEndpoint: new UntypedFormControl('', [requiredValidator]),
audience: new UntypedFormControl('' ),
});
this.authService
@@ -178,6 +179,7 @@ export class ProviderJWTComponent {
req.setIssuer(this.issuer?.value);
req.setJwtEndpoint(this.jwtEndpoint?.value);
req.setKeysEndpoint(this.keysEndpoint?.value);
req.setAudience(this.audience?.value);
req.setProviderOptions(this.options);
this.loading = true;
this.service
@@ -204,6 +206,7 @@ export class ProviderJWTComponent {
req.setIssuer(this.issuer?.value);
req.setJwtEndpoint(this.jwtEndpoint?.value);
req.setKeysEndpoint(this.keysEndpoint?.value);
req.setAudience(this.audience?.value);
req.setProviderOptions(this.options);
this.loading = true;
@@ -245,4 +248,8 @@ export class ProviderJWTComponent {
public get keysEndpoint(): AbstractControl | null {
return this.form.get('keysEndpoint');
}
public get audience(): AbstractControl | null {
return this.form.get('audience');
}
}
+2 -1
View File
@@ -2360,7 +2360,8 @@
"DESCRIPTION": "أدخل البيانات لمزود هوية JWT.",
"HEADERNAME": "اسم الرأس",
"JWTENDPOINT": "نقطة نهاية JWT",
"JWTKEYSENDPOINT": "نقطة نهاية مفاتيح JWT"
"JWTKEYSENDPOINT": "نقطة نهاية مفاتيح JWT",
"AUDIENCE": "الجمهور"
},
"APPLE": {
"TEAMID": "معرف الفريق",
+2 -1
View File
@@ -2371,7 +2371,8 @@
"DESCRIPTION": "Въведете данните за JWT Identity Provider.",
"HEADERNAME": "Име на заглавката",
"JWTENDPOINT": "Крайна точка на JWT",
"JWTKEYSENDPOINT": "Крайна точка на JWT ключове"
"JWTKEYSENDPOINT": "Крайна точка на JWT ключове",
"AUDIENCE": "Аудитория"
},
"APPLE": {
"TEAMID": "Team ID",
+2 -1
View File
@@ -2363,7 +2363,8 @@
"DESCRIPTION": "Zadejte data pro poskytovatele identity JWT.",
"HEADERNAME": "Název hlavičky",
"JWTENDPOINT": "JWT koncový bod",
"JWTKEYSENDPOINT": "Koncový bod klíčů JWT"
"JWTKEYSENDPOINT": "Koncový bod klíčů JWT",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "ID týmu",
+2 -1
View File
@@ -2362,7 +2362,8 @@
"DESCRIPTION": "Geben Sie die Daten JWT Identitätsanbieter ein. ",
"HEADERNAME": "Header Name",
"JWTENDPOINT": "JWT Endpoint",
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
"AUDIENCE": "Audience"
},
"TOAST": {
"SAVED": "Erfolgreich gespeichert.",
+2 -1
View File
@@ -2371,7 +2371,8 @@
"DESCRIPTION": "Enter the data for JWT Identity Provider.",
"HEADERNAME": "Header Name",
"JWTENDPOINT": "JWT Endpoint",
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "Team ID",
+2 -1
View File
@@ -2359,7 +2359,8 @@
"DESCRIPTION": "Introduce los datos para el proveedor de identidad JWT.",
"HEADERNAME": "Nombre de cabecera",
"JWTENDPOINT": "JWT Endpoint",
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
"AUDIENCE": "Audience"
},
"TOAST": {
"SAVED": "Guardado con éxito.",
+2 -1
View File
@@ -2363,7 +2363,8 @@
"DESCRIPTION": "Entrez les données pour le fournisseur d'identité JWT.",
"HEADERNAME": "Nom de l'en-tête",
"JWTENDPOINT": "Point de terminaison JWT",
"JWTKEYSENDPOINT": "Point de terminaison des clés JWT"
"JWTKEYSENDPOINT": "Point de terminaison des clés JWT",
"AUDIENCE": "Audience"
},
"TOAST": {
"SAVED": "Enregistré avec succès.",
+2 -1
View File
@@ -2364,7 +2364,8 @@
"DESCRIPTION": "Add meg az adatokat a JWT azonosítószolgáltatóhoz.",
"HEADERNAME": "Fejléc neve",
"JWTENDPOINT": "JWT végpont",
"JWTKEYSENDPOINT": "JWT kulcsok végpont"
"JWTKEYSENDPOINT": "JWT kulcsok végpont",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "Csapatazonosító",
+2 -1
View File
@@ -2364,7 +2364,8 @@
"DESCRIPTION": "Masukkan data Penyedia Identitas JWT.",
"HEADERNAME": "Nama Tajuk",
"JWTENDPOINT": "Titik Akhir JWT",
"JWTKEYSENDPOINT": "Titik Akhir Kunci JWT"
"JWTKEYSENDPOINT": "Titik Akhir Kunci JWT",
"AUDIENCE": "Audiens"
},
"APPLE": {
"TEAMID": "ID tim",
+2 -1
View File
@@ -2363,7 +2363,8 @@
"DESCRIPTION": "Inserisci i dati per il JWT Identity Provider.",
"HEADERNAME": "Header Name",
"JWTENDPOINT": "JWT Endpoint",
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
"AUDIENCE": "Audience"
},
"TOAST": {
"SAVED": "Salvato con successo.",
+2 -1
View File
@@ -2366,7 +2366,8 @@
"DESCRIPTION": "JWT Identity Providerの情報を入力する。",
"HEADERNAME": "ヘッダー名",
"JWTENDPOINT": "JWTエンドポイント",
"JWTKEYSENDPOINT": "JWTキーエンドポイント"
"JWTKEYSENDPOINT": "JWTキーエンドポイント",
"AUDIENCE": "オーディエンス"
},
"APPLE": {
"TEAMID": "チームID",
+2 -1
View File
@@ -2366,7 +2366,8 @@
"DESCRIPTION": "JWT ID 제공자에 필요한 데이터를 입력하세요.",
"HEADERNAME": "헤더 이름",
"JWTENDPOINT": "JWT 엔드포인트",
"JWTKEYSENDPOINT": "JWT 키 엔드포인트"
"JWTKEYSENDPOINT": "JWT 키 엔드포인트",
"AUDIENCE": "청중"
},
"APPLE": {
"TEAMID": "팀 ID",
+2 -1
View File
@@ -2359,7 +2359,8 @@
"DESCRIPTION": "Внесете ги податоците за JWT IDP.",
"HEADERNAME": "Име на хедер",
"JWTENDPOINT": "JWT Крајна точка",
"JWTKEYSENDPOINT": "JWT Крајна точка за клучеви"
"JWTKEYSENDPOINT": "JWT Крајна точка за клучеви",
"AUDIENCE": "Аудиториум"
},
"TOAST": {
"SAVED": "Успешно зачувано.",
+2 -1
View File
@@ -2366,7 +2366,8 @@
"DESCRIPTION": "Voer de gegevens in voor JWT Identity Provider.",
"HEADERNAME": "Header Naam",
"JWTENDPOINT": "JWT Eindpunt",
"JWTKEYSENDPOINT": "JWT Sleutels Eindpunt"
"JWTKEYSENDPOINT": "JWT Sleutels Eindpunt",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "Team ID",
+2 -1
View File
@@ -2362,7 +2362,8 @@
"DESCRIPTION": "Wprowadź dane dla dostawcy tożsamości JWT.",
"HEADERNAME": "Nazwa nagłówka",
"JWTENDPOINT": "Punkt końcowy JWT",
"JWTKEYSENDPOINT": "Punkt końcowy kluczy JWT"
"JWTKEYSENDPOINT": "Punkt końcowy kluczy JWT",
"AUDIENCE": "Odbiorca"
},
"TOAST": {
"SAVED": "Zapisano pomyślnie.",
+2 -1
View File
@@ -2358,7 +2358,8 @@
"DESCRIPTION": "Insira os dados para o Provedor de Identidade JWT.",
"HEADERNAME": "Nome do Cabeçalho",
"JWTENDPOINT": "Endpoint JWT",
"JWTKEYSENDPOINT": "Endpoint de Chaves JWT"
"JWTKEYSENDPOINT": "Endpoint de Chaves JWT",
"AUDIENCE": "Audiência"
},
"TOAST": {
"SAVED": "Salvo com sucesso.",
+2 -1
View File
@@ -2364,7 +2364,8 @@
"DESCRIPTION": "Introduceți datele pentru furnizorul de identitate JWT.",
"HEADERNAME": "Nume antet",
"JWTENDPOINT": "Punct final JWT",
"JWTKEYSENDPOINT": "Punct final chei JWT"
"JWTKEYSENDPOINT": "Punct final chei JWT",
"AUDIENCE": "Audiență"
},
"APPLE": {
"TEAMID": "ID echipă",
+2 -1
View File
@@ -2469,7 +2469,8 @@
"DESCRIPTION": "Введите данные JWT для поставщика идентификационных данных .",
"HEADERNAME": "Название заголовка",
"JWTENDPOINT": "Конечная точка JWT",
"JWTKEYSENDPOINT": "Конечная точка ключей JWT"
"JWTKEYSENDPOINT": "Конечная точка ключей JWT",
"AUDIENCE": "Аудитория"
},
"APPLE": {
"TEAMID": "Идентификатор команды",
+2 -1
View File
@@ -2370,7 +2370,8 @@
"DESCRIPTION": "Ange data för JWT-identitetsleverantören.",
"HEADERNAME": "Header-namn",
"JWTENDPOINT": "JWT-slutpunkt",
"JWTKEYSENDPOINT": "JWT-nycklar slutpunkt"
"JWTKEYSENDPOINT": "JWT-nycklar slutpunkt",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "Team-ID",
+2 -1
View File
@@ -2369,7 +2369,8 @@
"DESCRIPTION": "JWT Kimlik Sağlayıcısı için verileri girin.",
"HEADERNAME": "Başlık Adı",
"JWTENDPOINT": "JWT Uç Noktası",
"JWTKEYSENDPOINT": "JWT Anahtarları Uç Noktası"
"JWTKEYSENDPOINT": "JWT Anahtarları Uç Noktası",
"AUDIENCE": "Audience"
},
"APPLE": {
"TEAMID": "Takım ID",
+2 -1
View File
@@ -2370,7 +2370,8 @@
"DESCRIPTION": "Введіть дані для JWT постачальника ідентичності.",
"HEADERNAME": "Назва заголовка",
"JWTENDPOINT": "JWT кінцева точка",
"JWTKEYSENDPOINT": "JWT кінцева точка ключів"
"JWTKEYSENDPOINT": "JWT кінцева точка ключів",
"AUDIENCE": "Аудиторія"
},
"APPLE": {
"TEAMID": "ID команди",
+2 -1
View File
@@ -2374,7 +2374,8 @@
"DESCRIPTION": "输入 JWT 身份提供者的数据。",
"HEADERNAME": "请求头名称",
"JWTENDPOINT": "JWT 端点",
"JWTKEYSENDPOINT": "JWT Keys 端点"
"JWTKEYSENDPOINT": "JWT Keys 端点",
"AUDIENCE": "受众"
},
"APPLE": {
"TEAMID": "Team ID",
+12 -10
View File
@@ -265,22 +265,24 @@ func updateGenericOIDCProviderToCommand(req *admin_pb.UpdateGenericOIDCProviderR
func addJWTProviderToCommand(req *admin_pb.AddJWTProviderRequest) command.JWTProvider {
return command.JWTProvider{
Name: req.Name,
Issuer: req.Issuer,
JWTEndpoint: req.JwtEndpoint,
KeyEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
Name: req.GetName(),
Issuer: req.GetIssuer(),
JWTEndpoint: req.GetJwtEndpoint(),
KeyEndpoint: req.GetKeysEndpoint(),
HeaderName: req.GetHeaderName(),
Audience: req.GetAudience(),
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateJWTProviderToCommand(req *admin_pb.UpdateJWTProviderRequest) command.JWTProvider {
return command.JWTProvider{
Name: req.Name,
Issuer: req.Issuer,
JWTEndpoint: req.JwtEndpoint,
KeyEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
Name: req.GetName(),
Issuer: req.GetIssuer(),
JWTEndpoint: req.GetJwtEndpoint(),
KeyEndpoint: req.GetKeysEndpoint(),
HeaderName: req.GetHeaderName(),
Audience: req.GetAudience(),
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
+1
View File
@@ -529,6 +529,7 @@ func jwtConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.JWTIDP
Issuer: template.Issuer,
KeysEndpoint: template.KeysEndpoint,
HeaderName: template.HeaderName,
Audience: template.Audience,
},
}
}
+1
View File
@@ -197,6 +197,7 @@ func jwtConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.JWTIDPTemplate)
Issuer: template.Issuer,
KeysEndpoint: template.KeysEndpoint,
HeaderName: template.HeaderName,
Audience: template.Audience,
},
}
}
+12 -10
View File
@@ -258,22 +258,24 @@ func updateGenericOIDCProviderToCommand(req *mgmt_pb.UpdateGenericOIDCProviderRe
func addJWTProviderToCommand(req *mgmt_pb.AddJWTProviderRequest) command.JWTProvider {
return command.JWTProvider{
Name: req.Name,
Issuer: req.Issuer,
JWTEndpoint: req.JwtEndpoint,
KeyEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
Name: req.GetName(),
Issuer: req.GetIssuer(),
JWTEndpoint: req.GetJwtEndpoint(),
KeyEndpoint: req.GetKeysEndpoint(),
HeaderName: req.GetHeaderName(),
Audience: req.GetAudience(),
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateJWTProviderToCommand(req *mgmt_pb.UpdateJWTProviderRequest) command.JWTProvider {
return command.JWTProvider{
Name: req.Name,
Issuer: req.Issuer,
JWTEndpoint: req.JwtEndpoint,
KeyEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
Name: req.GetName(),
Issuer: req.GetIssuer(),
JWTEndpoint: req.GetJwtEndpoint(),
KeyEndpoint: req.GetKeysEndpoint(),
HeaderName: req.GetHeaderName(),
Audience: req.GetAudience(),
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
@@ -1090,6 +1090,7 @@ func (l *Login) jwtProvider(identityProvider *query.IDPTemplate) (*jwt.Provider,
identityProvider.JWTIDPTemplate.Endpoint,
identityProvider.JWTIDPTemplate.KeysEndpoint,
identityProvider.JWTIDPTemplate.HeaderName,
identityProvider.JWTIDPTemplate.Audience,
l.idpConfigAlg,
)
}
+1
View File
@@ -41,6 +41,7 @@ type JWTProvider struct {
JWTEndpoint string
KeyEndpoint string
HeaderName string
Audience string
IDPOptions idp.Options
}
+11 -1
View File
@@ -430,6 +430,7 @@ type JWTIDPWriteModel struct {
JWTEndpoint string
KeysEndpoint string
HeaderName string
Audience string
idp.Options
State domain.IDPState
@@ -465,6 +466,7 @@ func (wm *JWTIDPWriteModel) reduceAddedEvent(e *idp.JWTIDPAddedEvent) {
wm.JWTEndpoint = e.JWTEndpoint
wm.KeysEndpoint = e.KeysEndpoint
wm.HeaderName = e.HeaderName
wm.Audience = e.Audience
wm.Options = e.Options
wm.State = domain.IDPStateActive
}
@@ -485,6 +487,9 @@ func (wm *JWTIDPWriteModel) reduceChangedEvent(e *idp.JWTIDPChangedEvent) {
if e.HeaderName != nil {
wm.HeaderName = *e.HeaderName
}
if e.Audience != nil {
wm.Audience = *e.Audience
}
wm.Options.ReduceChanges(e.OptionChanges)
}
@@ -493,7 +498,8 @@ func (wm *JWTIDPWriteModel) NewChanges(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options idp.Options,
) ([]idp.JWTIDPChanges, error) {
changes := make([]idp.JWTIDPChanges, 0)
@@ -512,6 +518,9 @@ func (wm *JWTIDPWriteModel) NewChanges(
if wm.HeaderName != headerName {
changes = append(changes, idp.ChangeJWTHeaderName(headerName))
}
if wm.Audience != audience {
changes = append(changes, idp.ChangeJWTAudience(audience))
}
opts := wm.Options.Changes(options)
if !opts.IsZero() {
changes = append(changes, idp.ChangeJWTOptions(opts))
@@ -583,6 +592,7 @@ func (wm *JWTIDPWriteModel) ToProvider(callbackURL string, idpAlg crypto.Encrypt
wm.JWTEndpoint,
wm.KeysEndpoint,
wm.HeaderName,
wm.Audience,
idpAlg,
opts...,
)
+2
View File
@@ -940,6 +940,7 @@ func (c *Commands) prepareAddInstanceJWTProvider(a *instance.Aggregate, writeMod
provider.JWTEndpoint,
provider.KeyEndpoint,
provider.HeaderName,
provider.Audience,
provider.IDPOptions,
),
}, nil
@@ -988,6 +989,7 @@ func (c *Commands) prepareUpdateInstanceJWTProvider(a *instance.Aggregate, write
provider.JWTEndpoint,
provider.KeyEndpoint,
provider.HeaderName,
provider.Audience,
provider.IDPOptions,
)
if err != nil || event == nil {
+3 -1
View File
@@ -274,7 +274,8 @@ func (wm *InstanceJWTIDPWriteModel) NewChangedEvent(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options idp.Options,
) (*instance.JWTIDPChangedEvent, error) {
@@ -284,6 +285,7 @@ func (wm *InstanceJWTIDPWriteModel) NewChangedEvent(
jwtEndpoint,
keysEndpoint,
headerName,
audience,
options,
)
if err != nil || len(changes) == 0 {
+2
View File
@@ -911,6 +911,7 @@ func (c *Commands) prepareAddOrgJWTProvider(a *org.Aggregate, writeModel *OrgJWT
provider.JWTEndpoint,
provider.KeyEndpoint,
provider.HeaderName,
provider.Audience,
provider.IDPOptions,
),
}, nil
@@ -959,6 +960,7 @@ func (c *Commands) prepareUpdateOrgJWTProvider(a *org.Aggregate, writeModel *Org
provider.JWTEndpoint,
provider.KeyEndpoint,
provider.HeaderName,
provider.Audience,
provider.IDPOptions,
)
if err != nil || event == nil {
+3 -1
View File
@@ -276,7 +276,8 @@ func (wm *OrgJWTIDPWriteModel) NewChangedEvent(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options idp.Options,
) (*org.JWTIDPChangedEvent, error) {
@@ -286,6 +287,7 @@ func (wm *OrgJWTIDPWriteModel) NewChangedEvent(
jwtEndpoint,
keysEndpoint,
headerName,
audience,
options,
)
if err != nil || len(changes) == 0 {
+3 -1
View File
@@ -28,6 +28,7 @@ type Provider struct {
issuer string
jwtEndpoint string
keysEndpoint string
audience string
isLinkingAllowed bool
isCreationAllowed bool
isAutoCreation bool
@@ -67,13 +68,14 @@ func WithAutoUpdate() ProviderOpts {
}
// New creates a JWT provider
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName, audience string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
provider := &Provider{
name: name,
issuer: issuer,
jwtEndpoint: jwtEndpoint,
keysEndpoint: keysEndpoint,
headerName: headerName,
audience: audience,
encryptionAlg: encryptionAlg,
}
for _, option := range options {
+9
View File
@@ -20,6 +20,7 @@ func TestProvider_BeginAuth(t *testing.T) {
jwtEndpoint string
keysEndpoint string
headerName string
audience string
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
}
type args struct {
@@ -43,6 +44,7 @@ func TestProvider_BeginAuth(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -64,6 +66,7 @@ func TestProvider_BeginAuth(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -83,6 +86,7 @@ func TestProvider_BeginAuth(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -108,6 +112,7 @@ func TestProvider_BeginAuth(t *testing.T) {
tt.fields.jwtEndpoint,
tt.fields.keysEndpoint,
tt.fields.headerName,
tt.fields.audience,
tt.fields.encryptionAlg(t),
)
require.NoError(t, err)
@@ -135,6 +140,7 @@ func TestProvider_Options(t *testing.T) {
jwtEndpoint string
keysEndpoint string
headerName string
audience string
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
opts []ProviderOpts
}
@@ -159,6 +165,7 @@ func TestProvider_Options(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -181,6 +188,7 @@ func TestProvider_Options(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -211,6 +219,7 @@ func TestProvider_Options(t *testing.T) {
tt.fields.jwtEndpoint,
tt.fields.keysEndpoint,
tt.fields.headerName,
tt.fields.audience,
tt.fields.encryptionAlg(t),
tt.fields.opts...,
)
+5
View File
@@ -100,6 +100,11 @@ func (s *Session) validateToken(ctx context.Context, token string) (*oidc.IDToke
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
}
if s.Provider.audience != "" {
if err = oidc.CheckAudience(claims, s.Provider.audience); err != nil {
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
}
}
return claims, nil
}
@@ -27,6 +27,7 @@ func TestSession_FetchUser(t *testing.T) {
jwtEndpoint string
keysEndpoint string
headerName string
audience string
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
httpMock func(issuer string)
authURL string
@@ -60,6 +61,7 @@ func TestSession_FetchUser(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -83,6 +85,36 @@ func TestSession_FetchUser(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
httpMock: func(issuer string) {
gock.New(issuer).
Get("/keys").
Reply(200).
JSON(keys(t))
},
authURL: "https://auth.com/jwt?authRequestID=testState",
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
Token: &oauth2.Token{},
IDToken: "invalidToken",
},
},
want: want{
err: func(err error) bool {
return errors.Is(err, ErrInvalidToken)
},
},
},
{
name: "invalid token (audience)",
fields: fields{
issuer: "https://jwt.com",
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "audience",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -214,6 +246,69 @@ func TestSession_FetchUser(t *testing.T) {
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "clientID",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
httpMock: func(issuer string) {
gock.New(issuer).
Get("/keys").
Reply(200).
JSON(keys(t))
},
authURL: "https://auth.com/jwt?authRequestID=testState",
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
Token: &oauth2.Token{},
IDToken: idToken(t, "https://jwt.com", time.Now().Add(time.Hour), 0),
IDTokenClaims: &oidc.IDTokenClaims{
TokenClaims: oidc.TokenClaims{
Subject: "sub",
},
UserInfoProfile: oidc.UserInfoProfile{
Picture: "picture",
Name: "firstname lastname",
GivenName: "firstname",
FamilyName: "lastname",
Nickname: "nickname",
PreferredUsername: "username",
Profile: "profile",
Locale: oidc.NewLocale(language.English),
},
UserInfoEmail: oidc.UserInfoEmail{
Email: "email",
EmailVerified: oidc.Bool(true),
},
UserInfoPhone: oidc.UserInfoPhone{
PhoneNumber: "phone",
PhoneNumberVerified: true,
},
},
},
},
want: want{
id: "sub",
firstName: "firstname",
lastName: "lastname",
displayName: "firstname lastname",
nickName: "nickname",
preferredUsername: "username",
email: "email",
isEmailVerified: true,
phone: "phone",
isPhoneVerified: true,
preferredLanguage: language.English,
avatarURL: "picture",
profile: "profile",
},
},
{
name: "successful fetch (no audience check)",
fields: fields{
issuer: "https://jwt.com",
jwtEndpoint: "https://auth.com/jwt",
keysEndpoint: "https://jwt.com/keys",
headerName: "jwt-header",
audience: "",
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
},
@@ -281,6 +376,7 @@ func TestSession_FetchUser(t *testing.T) {
tt.fields.jwtEndpoint,
tt.fields.keysEndpoint,
tt.fields.headerName,
tt.fields.audience,
tt.fields.encryptionAlg(t),
)
require.NoError(t, err)
+13
View File
@@ -82,6 +82,7 @@ type JWTIDPTemplate struct {
KeysEndpoint string
HeaderName string
Endpoint string
Audience string
}
type AzureADIDPTemplate struct {
@@ -355,6 +356,10 @@ var (
name: projection.JWTHeaderNameCol,
table: jwtIdpTemplateTable,
}
JWTAudienceCol = Column{
name: projection.JWTAudienceCol,
table: jwtIdpTemplateTable,
}
)
var (
@@ -913,6 +918,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
JWTEndpointCol.identifier(),
JWTKeysEndpointCol.identifier(),
JWTHeaderNameCol.identifier(),
JWTAudienceCol.identifier(),
// azure
AzureADIDCol.identifier(),
AzureADClientIDCol.identifier(),
@@ -1034,6 +1040,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
jwtEndpoint := sql.NullString{}
jwtKeysEndpoint := sql.NullString{}
jwtHeaderName := sql.NullString{}
jwtAudience := sql.NullString{}
azureadID := sql.NullString{}
azureadClientID := sql.NullString{}
@@ -1153,6 +1160,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
&jwtEndpoint,
&jwtKeysEndpoint,
&jwtHeaderName,
&jwtAudience,
// azure
&azureadID,
&azureadClientID,
@@ -1273,6 +1281,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
KeysEndpoint: jwtKeysEndpoint.String,
HeaderName: jwtHeaderName.String,
Endpoint: jwtEndpoint.String,
Audience: jwtAudience.String,
}
}
if azureadID.Valid {
@@ -1429,6 +1438,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
JWTEndpointCol.identifier(),
JWTKeysEndpointCol.identifier(),
JWTHeaderNameCol.identifier(),
JWTAudienceCol.identifier(),
// azure
AzureADIDCol.identifier(),
AzureADClientIDCol.identifier(),
@@ -1555,6 +1565,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
jwtEndpoint := sql.NullString{}
jwtKeysEndpoint := sql.NullString{}
jwtHeaderName := sql.NullString{}
jwtAudience := sql.NullString{}
azureadID := sql.NullString{}
azureadClientID := sql.NullString{}
@@ -1674,6 +1685,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
&jwtEndpoint,
&jwtKeysEndpoint,
&jwtHeaderName,
&jwtAudience,
// azure
&azureadID,
&azureadClientID,
@@ -1793,6 +1805,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
KeysEndpoint: jwtKeysEndpoint.String,
HeaderName: jwtHeaderName.String,
Endpoint: jwtEndpoint.String,
Audience: jwtAudience.String,
}
}
if azureadID.Valid {
+25
View File
@@ -54,6 +54,7 @@ var (
` projections.idp_templates6_jwt.jwt_endpoint,` +
` projections.idp_templates6_jwt.keys_endpoint,` +
` projections.idp_templates6_jwt.header_name,` +
` projections.idp_templates6_jwt.audience,` +
// azure
` projections.idp_templates6_azure.idp_id,` +
` projections.idp_templates6_azure.client_id,` +
@@ -185,6 +186,7 @@ var (
"jwt_endpoint",
"keys_endpoint",
"header_name",
"audience",
// azure
"idp_id",
"client_id",
@@ -303,6 +305,7 @@ var (
` projections.idp_templates6_jwt.jwt_endpoint,` +
` projections.idp_templates6_jwt.keys_endpoint,` +
` projections.idp_templates6_jwt.header_name,` +
` projections.idp_templates6_jwt.audience,` +
// azure
` projections.idp_templates6_azure.idp_id,` +
` projections.idp_templates6_azure.client_id,` +
@@ -435,6 +438,7 @@ var (
"jwt_endpoint",
"keys_endpoint",
"header_name",
"audience",
// azure
"idp_id",
"client_id",
@@ -593,6 +597,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -749,6 +754,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -903,6 +909,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
"jwt",
"keys",
"header",
"audience",
// azure
nil,
nil,
@@ -1006,6 +1013,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
Endpoint: "jwt",
KeysEndpoint: "keys",
HeaderName: "header",
Audience: "audience",
},
},
},
@@ -1055,6 +1063,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1206,6 +1215,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1357,6 +1367,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1509,6 +1520,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1660,6 +1672,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1817,6 +1830,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -1989,6 +2003,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2142,6 +2157,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2323,6 +2339,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2504,6 +2521,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2658,6 +2676,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2777,6 +2796,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -2896,6 +2916,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -3015,6 +3036,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -3134,6 +3156,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
nil,
nil,
nil,
nil,
// azure
nil,
nil,
@@ -3253,6 +3276,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
"jwt",
"keys",
"header",
"audience",
// azure
nil,
nil,
@@ -3508,6 +3532,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
Endpoint: "jwt",
KeysEndpoint: "keys",
HeaderName: "header",
Audience: "audience",
},
},
},
@@ -221,5 +221,9 @@ func (p *relationalTablesProjection) reduceJWTIDPChangedColumns(payload *domain.
payloadChanged = true
payload.Issuer = *idpEvent.Issuer
}
if idpEvent.Audience != nil && *idpEvent.Audience != payload.Audience {
payloadChanged = true
payload.Audience = *idpEvent.Audience
}
return payloadChanged
}
@@ -89,6 +89,7 @@ const (
JWTEndpointCol = "jwt_endpoint"
JWTKeysEndpointCol = "keys_endpoint"
JWTHeaderNameCol = "header_name"
JWTAudienceCol = "audience"
AzureADIDCol = "idp_id"
AzureADInstanceIDCol = "instance_id"
@@ -258,6 +259,7 @@ func (*idpTemplateProjection) Init() *old_handler.Check {
handler.NewColumn(JWTEndpointCol, handler.ColumnTypeText),
handler.NewColumn(JWTKeysEndpointCol, handler.ColumnTypeText),
handler.NewColumn(JWTHeaderNameCol, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(JWTAudienceCol, handler.ColumnTypeText, handler.Nullable()),
},
handler.NewPrimaryKey(JWTInstanceIDCol, JWTIDCol),
IDPTemplateJWTSuffix,
@@ -1046,6 +1048,7 @@ func (p *idpTemplateProjection) reduceJWTIDPAdded(event eventstore.Event) (*hand
handler.NewCol(JWTEndpointCol, idpEvent.JWTEndpoint),
handler.NewCol(JWTKeysEndpointCol, idpEvent.KeysEndpoint),
handler.NewCol(JWTHeaderNameCol, idpEvent.HeaderName),
handler.NewCol(JWTAudienceCol, idpEvent.Audience),
},
handler.WithTableSuffix(IDPTemplateJWTSuffix),
),
@@ -2340,6 +2343,9 @@ func reduceJWTIDPChangedColumns(idpEvent idp.JWTIDPChangedEvent) []handler.Colum
if idpEvent.Issuer != nil {
jwtCols = append(jwtCols, handler.NewCol(JWTIssuerCol, *idpEvent.Issuer))
}
if idpEvent.Audience != nil {
jwtCols = append(jwtCols, handler.NewCol(JWTAudienceCol, *idpEvent.Audience))
}
return jwtCols
}
+11 -5
View File
@@ -4280,7 +4280,8 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true,
"autoLinkingOption": 1
"autoLinkingOption": 1,
"audience": "audience"
}`),
), instance.JWTIDPAddedEventMapper),
},
@@ -4311,7 +4312,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)",
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name, audience) VALUES ($1, $2, $3, $4, $5, $6, $7)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
@@ -4319,6 +4320,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
"jwt",
"keys",
"header",
"audience",
},
},
},
@@ -4342,7 +4344,8 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
"isLinkingAllowed": true,
"isAutoCreation": true,
"isAutoUpdate": true,
"autoLinkingOption": 1
"autoLinkingOption": 1,
"audience": "audience"
}`),
), org.JWTIDPAddedEventMapper),
},
@@ -4373,7 +4376,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)",
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name, audience) VALUES ($1, $2, $3, $4, $5, $6, $7)",
expectedArgs: []interface{}{
"idp-id",
"instance-id",
@@ -4381,6 +4384,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
"jwt",
"keys",
"header",
"audience",
},
},
},
@@ -4442,6 +4446,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
"jwtEndpoint": "jwt",
"keysEndpoint": "keys",
"headerName": "header",
"audience": "audience",
"isCreationAllowed": true,
"isLinkingAllowed": true,
"isAutoCreation": true,
@@ -4471,12 +4476,13 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.idp_templates6_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)",
expectedStmt: "UPDATE projections.idp_templates6_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer, audience) = ($1, $2, $3, $4, $5) WHERE (idp_id = $6) AND (instance_id = $7)",
expectedArgs: []interface{}{
"jwt",
"keys",
"header",
"issuer",
"audience",
"idp-id",
"instance-id",
},
+11 -1
View File
@@ -14,6 +14,7 @@ type JWTIDPAddedEvent struct {
JWTEndpoint string `json:"jwtEndpoint,omitempty"`
KeysEndpoint string `json:"keysEndpoint,omitempty"`
HeaderName string `json:"headerName,omitempty"`
Audience string `json:"audience,omitempty"`
Options
}
@@ -24,7 +25,8 @@ func NewJWTIDPAddedEvent(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options Options,
) *JWTIDPAddedEvent {
return &JWTIDPAddedEvent{
@@ -35,6 +37,7 @@ func NewJWTIDPAddedEvent(
JWTEndpoint: jwtEndpoint,
KeysEndpoint: keysEndpoint,
HeaderName: headerName,
Audience: audience,
Options: options,
}
}
@@ -69,6 +72,7 @@ type JWTIDPChangedEvent struct {
JWTEndpoint *string `json:"jwtEndpoint,omitempty"`
KeysEndpoint *string `json:"keysEndpoint,omitempty"`
HeaderName *string `json:"headerName,omitempty"`
Audience *string `json:"audience,omitempty"`
OptionChanges
}
@@ -122,6 +126,12 @@ func ChangeJWTHeaderName(headerName string) func(*JWTIDPChangedEvent) {
}
}
func ChangeJWTAudience(audience string) func(*JWTIDPChangedEvent) {
return func(e *JWTIDPChangedEvent) {
e.Audience = &audience
}
}
func ChangeJWTOptions(options OptionChanges) func(*JWTIDPChangedEvent) {
return func(e *JWTIDPChangedEvent) {
e.OptionChanges = options
+3 -1
View File
@@ -304,7 +304,8 @@ func NewJWTIDPAddedEvent(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options idp.Options,
) *JWTIDPAddedEvent {
@@ -321,6 +322,7 @@ func NewJWTIDPAddedEvent(
jwtEndpoint,
keysEndpoint,
headerName,
audience,
options,
),
}
+3 -1
View File
@@ -304,7 +304,8 @@ func NewJWTIDPAddedEvent(
issuer,
jwtEndpoint,
keysEndpoint,
headerName string,
headerName,
audience string,
options idp.Options,
) *JWTIDPAddedEvent {
@@ -321,6 +322,7 @@ func NewJWTIDPAddedEvent(
jwtEndpoint,
keysEndpoint,
headerName,
audience,
options,
),
}
+14
View File
@@ -6542,6 +6542,13 @@ message AddJWTProviderRequest {
string keys_endpoint = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
string header_name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
zitadel.idp.v1.Options provider_options = 6;
string audience = 7 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
description: "the expected audience in the JWT, if not provided the audience is not validated";
}
];
}
message AddJWTProviderResponse {
@@ -6562,6 +6569,13 @@ message UpdateJWTProviderRequest {
string keys_endpoint = 5 [(validate.rules).string = {max_len: 200}];
string header_name = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
zitadel.idp.v1.Options provider_options = 7;
string audience = 8 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
description: "the expected audience in the JWT, if not provided the audience is not validated";
}
];
}
message UpdateJWTProviderResponse {
+7
View File
@@ -195,6 +195,13 @@ message JWTConfig {
description: "the name of the header where the JWT is sent in, default is authorization";
}
];
string audience = 5 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
description: "the expected audience in the JWT, if not provided the audience is not validated";
}
];
}
message IDPIDQuery {
+7
View File
@@ -133,6 +133,13 @@ message JWTConfig {
"\"x-auth-token\"";
}
];
// The audience is the expected audience in the JWT, if not configured, the audience is not validated.
string audience = 5 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
}
];
}
message OAuthConfig {
+14
View File
@@ -13291,6 +13291,13 @@ message AddJWTProviderRequest {
string keys_endpoint = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
string header_name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
zitadel.idp.v1.Options provider_options = 6;
string audience = 7 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
description: "the expected audience in the JWT, if not provided the audience is not validated";
}
];
}
message AddJWTProviderResponse {
@@ -13311,6 +13318,13 @@ message UpdateJWTProviderRequest {
string keys_endpoint = 5 [(validate.rules).string = {max_len: 200}];
string header_name = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
zitadel.idp.v1.Options provider_options = 7;
string audience = 8 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my-audience\"";
description: "the expected audience in the JWT, if not provided the audience is not validated";
}
];
}
message UpdateJWTProviderResponse {