.NET Aspire Keycloak Integration (Vorschau)
umfasst:Hostingintegration und Client-Integration
Keycloak ist eine Open Source Identity and Access Management-Lösung für moderne Anwendungen und Dienste. Mit der .NET AspireKeycloak-Integration können Sie eine Verbindung zu vorhandenen Keycloak-Instanzen herstellen oder neue Instanzen aus .NET mit dem quay.io/keycloak/keycloak
-Containerimageerstellen.
Hosting-Integration
Die .NET AspireKeycloak Hostintegrationsmodelle modellieren den server als KeycloakResource Typ. Um auf diese Typen und APIs zuzugreifen, fügen Sie das NuGet-Paket 📦Aspire.Hosting.Keycloak im Projekt des App-Hosts hinzu.
dotnet add package Aspire.Hosting.Keycloak --prerelease
Weitere Informationen finden Sie unter dotnet add package oder Paketabhängigkeiten in .NET-Anwendungen verwalten.
Fügen Sie die Ressource Keycloak hinzu
Rufen Sie in Ihrem App-Hostprojekt AddKeycloak auf, um einen Keycloak Ressourcen-Generator hinzuzufügen und zurückzugeben. Verketten sie einen Aufruf an den zurückgegebenen Ressourcen-Generator, um die Keycloakzu konfigurieren.
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder.AddKeycloak("keycloak", 8080);
var apiService = builder.AddProject<Projects.Keycloak_ApiService>("apiservice")
.WithReference(keycloak)
.WaitFor(keycloak);
builder.AddProject<Projects.Keycloak_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(keycloak)
.WithReference(apiService)
.WaitFor(apiService);
// After adding all resources, run the app...
Tipp
Verwenden Sie für die lokale Entwicklung einen stabilen Port für die Keycloak Ressource (8080
im vorherigen Beispiel). Es kann sich um einen beliebigen Port handeln, aber dieser sollte stabil sein, um Probleme mit Browser-Cookies zu vermeiden, die OIDC-Token (einschließlich der Autoritäts-URL, mit Port) über die Lebensdauer des -App-Hostshinaus speichern.
Wenn .NET.NET Aspire dem App-Host ein Containerimage hinzufügt, wie im vorherigen Beispiel mit dem quay.io/keycloak/keycloak
-Image gezeigt, wird eine neue Keycloak Instanz auf dem lokalen Computer erstellt. Die Keycloak-Ressource enthält Standardanmeldeinformationen:
-
KEYCLOAK_ADMIN
: Ein Wert vonadmin
. -
KEYCLOAK_ADMIN_PASSWORD
:password
zufällig mithilfe der CreateDefaultPasswordParameter-Methode generiert.
Wenn der App-Host ausgeführt wird, wird das Kennwort im geheimen Speicher des App-Hosts gespeichert. Sie wird dem Abschnitt Parameters
hinzugefügt, zum Beispiel:
{
"Parameters:keycloak-password": "<THE_GENERATED_PASSWORD>"
}
Der Name des Parameters ist keycloak-password
, aber tatsächlich wird nur der Ressourcenname mit einem -password
Suffix formatiert. Weitere Informationen finden Sie unter sichere Speicherung von App-Geheimnissen in der Entwicklung in ASP.NET Core und Hinzufügen der Ressource Keycloak.
Die WithReference-Methode konfiguriert eine Verbindung in ExampleProject
mit dem Namen keycloak
, und WaitFor weist den App-Host an, den abhängigen Dienst erst dann zu starten, wenn die keycloak
-Ressource bereit ist.
Tipp
Wenn Sie lieber eine Verbindung mit einer vorhandenen Keycloak Instanz herstellen möchten, rufen Sie stattdessen AddConnectionString auf. Weitere Informationen finden Sie unter Referenzieren vorhandener Ressourcen.
Füge die Ressource Keycloak mit Datenvolumen hinzu.
Rufen Sie die WithDataVolume-Methode für die Keycloak-Ressource auf, um der Keycloak-Ressource ein Datenvolume hinzuzufügen:
var keycloak = builder.AddKeycloak("keycloak", 8080)
.WithDataVolume();
var apiService = builder.AddProject<Projects.Keycloak_ApiService>("apiservice")
.WithReference(keycloak)
.WaitFor(keycloak);
builder.AddProject<Projects.Keycloak_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(keycloak)
.WithReference(apiService)
.WaitFor(apiService);
// After adding all resources, run the app...
Das Datenvolume wird verwendet, um die Keycloak Daten außerhalb des Lebenszyklus des Containers zu speichern. Das Datenvolumen wird im Pfad /opt/keycloak/data
im Container Keycloak bereitgestellt, und wenn kein name
Parameter bereitgestellt wird, wird der Name zufällig generiert. Weitere Informationen zu Datenvolumes und Details dazu, warum sie gegenüber Bind-Mountsbevorzugt werden, finden Sie in der Docker-Dokumentation: Volumes.
Warnung
Die Administratoranmeldeinformationen werden im Datenvolume gespeichert. Wenn Sie ein Datenvolume verwenden und sich die Anmeldeinformationen ändern, funktioniert dies nicht mehr, bis Sie das Volume löschen.
Füge Keycloak-Ressource mit Daten-Bind-Mount hinzu
Rufen Sie die WithDataBindMount-Methode auf, um der Keycloak-Ressource eine Datenbindung hinzuzufügen:
var keycloak = builder.AddKeycloak("keycloak", 8080)
.WithDataBindMount(@"C:\Keycloak\Data");
var apiService = builder.AddProject<Projects.Keycloak_ApiService>("apiservice")
.WithReference(keycloak)
.WaitFor(keycloak);
builder.AddProject<Projects.Keycloak_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(keycloak)
.WithReference(apiService)
.WaitFor(apiService);
// After adding all resources, run the app...
Wichtig
Daten--Bind-Mounts haben im Vergleich zu -Volumeseine eingeschränkte Funktionalität. Diese bieten eine bessere Leistung, Portabilität und Sicherheit, wodurch sie für Produktionsumgebungen besser geeignet sind. Bind-Einhängepunkte ermöglichen jedoch direkten Zugriff und die Bearbeitung von Dateien auf dem Hostsystem, was ideal für die Entwicklung und das Testen ist, wo Echtzeitänderungen erforderlich sind.
Datenbindungs-Bereitstellungen basieren auf dem Dateisystem des Hostcomputers, um die Keycloak Daten über Containerneustarts hinweg beizubehalten. Der Datenbindemount wird auf dem Pfad C:\Keycloak\Data
unter Windows (oder /Keycloak/Data
auf Unix) auf dem Hostcomputer im Container Keycloak bereitgestellt. Weitere Informationen zu Daten-Bind-Mounts finden Sie in den Docker-Dokumenten: Bind-Mounts.
Füge die Ressource Keycloak mit Parametern hinzu
Wenn Sie explizit den Administratorbenutzernamen und das vom Containerimage verwendete Kennwort angeben möchten, können Sie diese Anmeldeinformationen als Parameter angeben. Betrachten Sie das folgende alternative Beispiel:
var builder = DistributedApplication.CreateBuilder(args);
var username = builder.AddParameter("username");
var password = builder.AddParameter("password", secret: true);
var keycloak = builder.AddKeycloak("keycloak", 8080, username, password);
var apiService = builder.AddProject<Projects.Keycloak_ApiService>("apiservice")
.WithReference(keycloak)
.WaitFor(keycloak);
builder.AddProject<Projects.Keycloak_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(keycloak)
.WithReference(apiService)
.WaitFor(apiService);
// After adding all resources, run the app...
Die Parameter username
und password
werden in der Regel als Umgebungsvariablen oder geheime Schlüssel bereitgestellt. Die Parameter werden verwendet, um die KEYCLOAK_ADMIN
- und KEYCLOAK_ADMIN_PASSWORD
Umgebungsvariablen im Container festzulegen. Weitere Informationen zum Bereitstellen von Parametern finden Sie unter externe Parameter.
Fügen Sie die Ressource Keycloak mit dem Bereichsimport hinzu.
Rufen Sie zum Importieren eines Bereichs in Keycloakdie WithRealmImport-Methode auf:
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder.AddKeycloak("keycloak", 8080)
.WithDataVolume()
.WithRealmImport("./Realms");
var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice")
.WithReference(keycloak)
.WaitFor(keycloak);
builder.AddProject<Projects.AspireApp_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(keycloak)
.WithReference(apiService)
.WaitFor(apiService);
builder.Build().Run();
Die Bereichsimportdateien werden an /opt/keycloak/data/import
im Container Keycloak eingehängt. Bereichsimportdateien sind JSON-Dateien, die die Bereichskonfiguration darstellen. Weitere Informationen zum Bereichsimport finden Sie unter Keycloak Dokumente: Importieren eines Bereichs.
Die folgende JSON-Datei könnte beispielsweise dem App-Hostprojekt in einem /Realms Ordner hinzugefügt werden, um als Quellbereichskonfigurationsdatei zu dienen:
Beispiel zum Umschalten des Bereichs JSON.
{
"id": "86683c73-be28-4380-a014-6316c0404192",
"realm": "WeatherShop",
"notBefore": 0,
"defaultSignatureAlgorithm": "RS256",
"revokeRefreshToken": false,
"refreshTokenMaxReuse": 0,
"accessTokenLifespan": 300,
"accessTokenLifespanForImplicitFlow": 900,
"ssoSessionIdleTimeout": 1800,
"ssoSessionMaxLifespan": 36000,
"ssoSessionIdleTimeoutRememberMe": 0,
"ssoSessionMaxLifespanRememberMe": 0,
"offlineSessionIdleTimeout": 2592000,
"offlineSessionMaxLifespanEnabled": false,
"offlineSessionMaxLifespan": 5184000,
"clientSessionIdleTimeout": 0,
"clientSessionMaxLifespan": 0,
"clientOfflineSessionIdleTimeout": 0,
"clientOfflineSessionMaxLifespan": 0,
"accessCodeLifespan": 60,
"accessCodeLifespanUserAction": 300,
"accessCodeLifespanLogin": 1800,
"actionTokenGeneratedByAdminLifespan": 43200,
"actionTokenGeneratedByUserLifespan": 300,
"oauth2DeviceCodeLifespan": 600,
"oauth2DevicePollingInterval": 5,
"enabled": true,
"sslRequired": "external",
"registrationAllowed": true,
"registrationEmailAsUsername": false,
"rememberMe": false,
"verifyEmail": false,
"loginWithEmailAllowed": true,
"duplicateEmailsAllowed": false,
"resetPasswordAllowed": false,
"editUsernameAllowed": false,
"bruteForceProtected": false,
"permanentLockout": false,
"maxTemporaryLockouts": 0,
"maxFailureWaitSeconds": 900,
"minimumQuickLoginWaitSeconds": 60,
"waitIncrementSeconds": 60,
"quickLoginCheckMilliSeconds": 1000,
"maxDeltaTimeSeconds": 43200,
"failureFactor": 30,
"roles": {
"realm": [
{
"id": "79e15e0c-7084-4595-9066-c852bc5a6aca",
"name": "uma_authorization",
"description": "${role_uma_authorization}",
"composite": false,
"clientRole": false,
"containerId": "86683c73-be28-4380-a014-6316c0404192",
"attributes": {}
},
{
"id": "f2bd959d-ed9d-4409-af6d-206a4a52cc23",
"name": "default-roles-weathershop",
"description": "${role_default-roles}",
"composite": true,
"composites": {
"realm": [ "offline_access", "uma_authorization" ],
"client": {
"account": [ "view-profile", "manage-account" ]
}
},
"clientRole": false,
"containerId": "86683c73-be28-4380-a014-6316c0404192",
"attributes": {}
},
{
"id": "5e1d3cf6-c7ac-478d-a70c-4299abf58490",
"name": "offline_access",
"description": "${role_offline-access}",
"composite": false,
"clientRole": false,
"containerId": "86683c73-be28-4380-a014-6316c0404192",
"attributes": {}
}
],
"client": {
"realm-management": [
{
"id": "fe6e42fe-8629-40da-9afe-1179fc964988",
"name": "manage-users",
"description": "${role_manage-users}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "f82abb6c-239c-4533-afbd-a7aa03937204",
"name": "view-users",
"description": "${role_view-users}",
"composite": true,
"composites": {
"client": {
"realm-management": [ "query-groups", "query-users" ]
}
},
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "1eb57351-1302-45e5-924a-9b0dc337a2bb",
"name": "view-events",
"description": "${role_view-events}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "df3a077e-9bd4-4924-8281-cab7c7fd73e3",
"name": "manage-authorization",
"description": "${role_manage-authorization}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "d9fcb43a-3bad-492c-9af9-f199a6382064",
"name": "query-groups",
"description": "${role_query-groups}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "1dbdaf2b-a29c-4c54-86b7-d7c338e7672f",
"name": "realm-admin",
"description": "${role_realm-admin}",
"composite": true,
"composites": {
"client": {
"realm-management": [ "view-users", "manage-users", "view-events", "query-groups", "manage-authorization", "query-users", "manage-realm", "view-identity-providers", "create-client", "view-authorization", "query-clients", "view-clients", "query-realms", "impersonation", "view-realm", "manage-events", "manage-identity-providers", "manage-clients" ]
}
},
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "4c1ff7e3-cc1d-4b1d-a88f-fb71416c742a",
"name": "query-users",
"description": "${role_query-users}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "284b35f8-5bc2-4482-8769-81d3594df5a3",
"name": "manage-realm",
"description": "${role_manage-realm}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "7e872c38-8a22-469f-92ca-ec67e95d3c33",
"name": "view-identity-providers",
"description": "${role_view-identity-providers}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "9f4c2563-7575-461e-b2c8-b2b87f314cb9",
"name": "create-client",
"description": "${role_create-client}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "8f92f45c-bfa0-4a66-9812-334fe223c8be",
"name": "query-clients",
"description": "${role_query-clients}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "2a0143cf-ad90-4f68-bcb2-a50aa358b070",
"name": "view-authorization",
"description": "${role_view-authorization}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "95cc13bf-1342-445a-99fd-141522a7e777",
"name": "view-clients",
"description": "${role_view-clients}",
"composite": true,
"composites": {
"client": {
"realm-management": [ "query-clients" ]
}
},
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "109f4b83-ba7d-4036-91e7-7e169cd4c30c",
"name": "query-realms",
"description": "${role_query-realms}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "17bcb2b7-3a35-4089-85ea-1d034303b5d6",
"name": "impersonation",
"description": "${role_impersonation}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "21c51846-5f22-4318-82b7-9e64e2d256f4",
"name": "view-realm",
"description": "${role_view-realm}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "a0599e32-b53b-43bf-a7f6-ac0507ed277d",
"name": "manage-events",
"description": "${role_manage-events}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "e732e665-efb7-4df0-8843-b22bf2fe4717",
"name": "manage-identity-providers",
"description": "${role_manage-identity-providers}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
},
{
"id": "6d1b10f2-4c51-4279-8418-d4b82c17f203",
"name": "manage-clients",
"description": "${role_manage-clients}",
"composite": false,
"clientRole": true,
"containerId": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"attributes": {}
}
],
"WeatherWeb": [],
"security-admin-console": [],
"admin-cli": [],
"account-console": [],
"broker": [
{
"id": "7184260f-55c4-454a-bf67-dade5b74df7e",
"name": "read-token",
"description": "${role_read-token}",
"composite": false,
"clientRole": true,
"containerId": "db2ab30c-b83b-499e-9545-decdc906a372",
"attributes": {}
}
],
"Postman": [],
"weather.api": [],
"account": [
{
"id": "b4a01a53-3ed0-4e96-8fd1-efb0c143a45d",
"name": "view-groups",
"description": "${role_view-groups}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "e9af1e5f-c0a5-4515-a77a-38fec79135d0",
"name": "delete-account",
"description": "${role_delete-account}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "526cc4f7-6cf8-4f2b-8241-de0e60d2fd47",
"name": "manage-consent",
"description": "${role_manage-consent}",
"composite": true,
"composites": {
"client": {
"account": [ "view-consent" ]
}
},
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "cf93d42f-ffd9-4b3f-bf8d-55aa934f2fe3",
"name": "view-applications",
"description": "${role_view-applications}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "f3b44155-fe06-4fea-8b8f-6954f54d48bb",
"name": "view-profile",
"description": "${role_view-profile}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "65a74b6a-a00f-46b6-8ead-6c051e78c37e",
"name": "manage-account",
"description": "${role_manage-account}",
"composite": true,
"composites": {
"client": {
"account": [ "manage-account-links" ]
}
},
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "c914cc47-8a49-4f30-9851-6f639c4e7adf",
"name": "manage-account-links",
"description": "${role_manage-account-links}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
},
{
"id": "261d0db4-28c7-4900-a156-01ab4e2483e5",
"name": "view-consent",
"description": "${role_view-consent}",
"composite": false,
"clientRole": true,
"containerId": "65816a45-48d3-4856-b052-c65cb03881d3",
"attributes": {}
}
]
}
},
"groups": [],
"defaultRole": {
"id": "f2bd959d-ed9d-4409-af6d-206a4a52cc23",
"name": "default-roles-weathershop",
"description": "${role_default-roles}",
"composite": true,
"clientRole": false,
"containerId": "86683c73-be28-4380-a014-6316c0404192"
},
"requiredCredentials": [ "password" ],
"otpPolicyType": "totp",
"otpPolicyAlgorithm": "HmacSHA1",
"otpPolicyInitialCounter": 0,
"otpPolicyDigits": 6,
"otpPolicyLookAheadWindow": 1,
"otpPolicyPeriod": 30,
"otpPolicyCodeReusable": false,
"otpSupportedApplications": [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ],
"localizationTexts": {},
"webAuthnPolicyRpEntityName": "keycloak",
"webAuthnPolicySignatureAlgorithms": [ "ES256" ],
"webAuthnPolicyRpId": "",
"webAuthnPolicyAttestationConveyancePreference": "not specified",
"webAuthnPolicyAuthenticatorAttachment": "not specified",
"webAuthnPolicyRequireResidentKey": "not specified",
"webAuthnPolicyUserVerificationRequirement": "not specified",
"webAuthnPolicyCreateTimeout": 0,
"webAuthnPolicyAvoidSameAuthenticatorRegister": false,
"webAuthnPolicyAcceptableAaguids": [],
"webAuthnPolicyExtraOrigins": [],
"webAuthnPolicyPasswordlessRpEntityName": "keycloak",
"webAuthnPolicyPasswordlessSignatureAlgorithms": [ "ES256" ],
"webAuthnPolicyPasswordlessRpId": "",
"webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
"webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
"webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
"webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
"webAuthnPolicyPasswordlessCreateTimeout": 0,
"webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
"webAuthnPolicyPasswordlessAcceptableAaguids": [],
"webAuthnPolicyPasswordlessExtraOrigins": [],
"scopeMappings": [
{
"clientScope": "offline_access",
"roles": [ "offline_access" ]
}
],
"clientScopeMappings": {
"account": [
{
"client": "account-console",
"roles": [ "manage-account", "view-groups" ]
}
]
},
"clients": [
{
"id": "bd03dd61-71bf-4f50-acfa-bfc2444ee1d2",
"clientId": "Postman",
"name": "",
"description": "",
"rootUrl": "",
"adminUrl": "",
"baseUrl": "",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [ "https://oauth.pstmn.io/v1/callback" ],
"webOrigins": [ "https://oauth.pstmn.io" ],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": true,
"protocol": "openid-connect",
"attributes": {
"oidc.ciba.grant.enabled": "false",
"client.secret.creation.time": "1718111570",
"backchannel.logout.session.required": "true",
"post.logout.redirect.uris": "+",
"oauth2.device.authorization.grant.enabled": "false",
"display.on.consent.screen": "false",
"backchannel.logout.revoke.offline.tokens": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "weather:all", "microprofile-jwt" ]
},
{
"id": "016c17d1-8e0f-4a67-9116-86b4691ba99c",
"clientId": "WeatherWeb",
"name": "",
"description": "",
"rootUrl": "",
"adminUrl": "",
"baseUrl": "",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [ "https://localhost:7085/signin-oidc" ],
"webOrigins": [ "https://localhost:7085" ],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": true,
"protocol": "openid-connect",
"attributes": {
"oidc.ciba.grant.enabled": "false",
"post.logout.redirect.uris": "https://localhost:7085/signout-callback-oidc",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.session.required": "true",
"backchannel.logout.revoke.offline.tokens": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "weather:all", "microprofile-jwt" ]
},
{
"id": "65816a45-48d3-4856-b052-c65cb03881d3",
"clientId": "account",
"name": "${client_account}",
"rootUrl": "${authBaseUrl}",
"baseUrl": "/realms/WeatherShop/account/",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [ "/realms/WeatherShop/account/*" ],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "437fda77-3ba1-4d7b-b192-808e4e62833b",
"clientId": "account-console",
"name": "${client_account-console}",
"rootUrl": "${authBaseUrl}",
"baseUrl": "/realms/WeatherShop/account/",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [ "/realms/WeatherShop/account/*" ],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+",
"pkce.code.challenge.method": "S256"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"protocolMappers": [
{
"id": "e4606d8a-a581-402c-9290-4e3b988f2090",
"name": "audience resolve",
"protocol": "openid-connect",
"protocolMapper": "oidc-audience-resolve-mapper",
"consentRequired": false,
"config": {}
}
],
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "f13fd042-6931-4032-a0ba-f63b364f8d56",
"clientId": "admin-cli",
"name": "${client_admin-cli}",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": false,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "db2ab30c-b83b-499e-9545-decdc906a372",
"clientId": "broker",
"name": "${client_broker}",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": true,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": false,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "0aa2db92-8cc4-490f-a084-55f5b889613a",
"clientId": "realm-management",
"name": "${client_realm-management}",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": true,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": false,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "e0cc9cef-924e-4799-a921-4811f3bb5d65",
"clientId": "security-admin-console",
"name": "${client_security-admin-console}",
"rootUrl": "${authAdminUrl}",
"baseUrl": "/admin/WeatherShop/console/",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [ "/admin/WeatherShop/console/*" ],
"webOrigins": [ "+" ],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"post.logout.redirect.uris": "+",
"pkce.code.challenge.method": "S256"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": false,
"nodeReRegistrationTimeout": 0,
"protocolMappers": [
{
"id": "254ac20c-6701-4095-82c6-6abd6669b9de",
"name": "locale",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "locale",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "locale",
"jsonType.label": "String"
}
}
],
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
},
{
"id": "4b5953fd-b218-41be-b061-58f37c1c7d26",
"clientId": "weather.api",
"name": "",
"description": "",
"rootUrl": "",
"adminUrl": "",
"baseUrl": "",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"secret": "**********",
"redirectUris": [ "/*" ],
"webOrigins": [ "/*" ],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": false,
"frontchannelLogout": true,
"protocol": "openid-connect",
"attributes": {
"oidc.ciba.grant.enabled": "false",
"client.secret.creation.time": "1718111354",
"backchannel.logout.session.required": "true",
"post.logout.redirect.uris": "+",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.revoke.offline.tokens": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes": [ "address", "phone", "offline_access", "microprofile-jwt" ]
}
],
"clientScopes": [
{
"id": "2a6322a2-2f6a-469f-b3c7-d0922db4ad46",
"name": "phone",
"description": "OpenID Connect built-in scope: phone",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"consent.screen.text": "${phoneScopeConsentText}"
},
"protocolMappers": [
{
"id": "ab515c55-d65b-42d3-9d3c-18921a8df065",
"name": "phone number",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "phoneNumber",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "phone_number",
"jsonType.label": "String"
}
},
{
"id": "bfaa5db4-137c-4824-bfae-ed77762872c2",
"name": "phone number verified",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "phoneNumberVerified",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "phone_number_verified",
"jsonType.label": "boolean"
}
}
]
},
{
"id": "52fc55cb-995e-4aa2-95ae-3b3d6601dc41",
"name": "weather:all",
"description": "",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"gui.order": "",
"consent.screen.text": ""
},
"protocolMappers": [
{
"id": "06d03e02-1e56-4bde-911d-bcf28aeba90f",
"name": "weather api audience",
"protocol": "openid-connect",
"protocolMapper": "oidc-audience-mapper",
"consentRequired": false,
"config": {
"included.client.audience": "weather.api",
"introspection.token.claim": "true",
"userinfo.token.claim": "false",
"id.token.claim": "false",
"lightweight.claim": "false",
"access.token.claim": "true"
}
}
]
},
{
"id": "292ded65-c85e-4c56-ad4d-8e886b9bb261",
"name": "email",
"description": "OpenID Connect built-in scope: email",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"consent.screen.text": "${emailScopeConsentText}"
},
"protocolMappers": [
{
"id": "42743882-7e0a-455e-b6a3-794ec8bf0f22",
"name": "email verified",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-property-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "emailVerified",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "email_verified",
"jsonType.label": "boolean"
}
},
{
"id": "b6dd2af9-e583-4d01-95fa-3f0db3ab0129",
"name": "email",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "email",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "email",
"jsonType.label": "String"
}
}
]
},
{
"id": "09a76939-4997-49f5-b88e-dfe54a2819f5",
"name": "offline_access",
"description": "OpenID Connect built-in scope: offline_access",
"protocol": "openid-connect",
"attributes": {
"consent.screen.text": "${offlineAccessScopeConsentText}",
"display.on.consent.screen": "true"
}
},
{
"id": "95ff8627-716e-49f0-b960-52185409d628",
"name": "profile",
"description": "OpenID Connect built-in scope: profile",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"consent.screen.text": "${profileScopeConsentText}"
},
"protocolMappers": [
{
"id": "b1ae43d1-9d52-40cd-9c6a-a8557ea63f9a",
"name": "picture",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "picture",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "picture",
"jsonType.label": "String"
}
},
{
"id": "b9e09b82-3e67-4175-b34a-419b24a13a7f",
"name": "zoneinfo",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "zoneinfo",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "zoneinfo",
"jsonType.label": "String"
}
},
{
"id": "06e88533-d2cc-4ae3-a25a-a17e93f69dee",
"name": "nickname",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "nickname",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "nickname",
"jsonType.label": "String"
}
},
{
"id": "b697c055-2fb9-4985-8919-33d9f524eaa9",
"name": "full name",
"protocol": "openid-connect",
"protocolMapper": "oidc-full-name-mapper",
"consentRequired": false,
"config": {
"id.token.claim": "true",
"introspection.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
},
{
"id": "70663048-2110-4271-a8f4-105e77fe2905",
"name": "profile",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "profile",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "profile",
"jsonType.label": "String"
}
},
{
"id": "85c992ed-4971-41f1-a4b8-c6263b29dff8",
"name": "website",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "website",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "website",
"jsonType.label": "String"
}
},
{
"id": "49e1d494-a72e-49de-a5de-8c2ad752205c",
"name": "birthdate",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "birthdate",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "birthdate",
"jsonType.label": "String"
}
},
{
"id": "a746724f-7622-4ad4-91ef-811da6c735ad",
"name": "updated at",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "updatedAt",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "updated_at",
"jsonType.label": "long"
}
},
{
"id": "d647d13f-9f96-49f3-b32a-62ad63c37d0e",
"name": "gender",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "gender",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "gender",
"jsonType.label": "String"
}
},
{
"id": "86204f6f-16ce-4c9f-9fca-f66b3f292554",
"name": "given name",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "firstName",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "given_name",
"jsonType.label": "String"
}
},
{
"id": "f4005bd9-18d2-4456-9e7c-98c5a637f063",
"name": "locale",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "locale",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "locale",
"jsonType.label": "String"
}
},
{
"id": "04b20a5a-1588-476c-a465-26a691320510",
"name": "family name",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "lastName",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "family_name",
"jsonType.label": "String"
}
},
{
"id": "f812580a-7863-44c3-bcf0-c3f441f0194e",
"name": "middle name",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "middleName",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "middle_name",
"jsonType.label": "String"
}
},
{
"id": "c2ae83c9-62c2-4a65-adef-c1d6fd126ec4",
"name": "username",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "username",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "preferred_username",
"jsonType.label": "String"
}
}
]
},
{
"id": "3ab2520f-feb4-43fd-9256-fa9f3e521aa7",
"name": "address",
"description": "OpenID Connect built-in scope: address",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"consent.screen.text": "${addressScopeConsentText}"
},
"protocolMappers": [
{
"id": "b083371e-07ae-4b01-9e8c-6a54b396359f",
"name": "address",
"protocol": "openid-connect",
"protocolMapper": "oidc-address-mapper",
"consentRequired": false,
"config": {
"user.attribute.formatted": "formatted",
"user.attribute.country": "country",
"introspection.token.claim": "true",
"user.attribute.postal_code": "postal_code",
"userinfo.token.claim": "true",
"user.attribute.street": "street",
"id.token.claim": "true",
"user.attribute.region": "region",
"access.token.claim": "true",
"user.attribute.locality": "locality"
}
}
]
},
{
"id": "fda66a99-e8b6-49e6-9186-0a7026ec0275",
"name": "web-origins",
"description": "OpenID Connect scope for add allowed web origins to the access token",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "false",
"display.on.consent.screen": "false",
"consent.screen.text": ""
},
"protocolMappers": [
{
"id": "4b12d4de-8c05-4251-9c8f-f801cfa3bf2a",
"name": "allowed web origins",
"protocol": "openid-connect",
"protocolMapper": "oidc-allowed-origins-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"access.token.claim": "true"
}
}
]
},
{
"id": "581928cd-35d7-4c79-a9d1-4e1c9c8ade7e",
"name": "acr",
"description": "OpenID Connect scope for add acr (authentication context class reference) to the token",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "false",
"display.on.consent.screen": "false"
},
"protocolMappers": [
{
"id": "d664d3db-be9f-4fee-a72a-be6a295c47f5",
"name": "acr loa level",
"protocol": "openid-connect",
"protocolMapper": "oidc-acr-mapper",
"consentRequired": false,
"config": {
"id.token.claim": "true",
"introspection.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}
]
},
{
"id": "9ac2f136-a665-4550-ac77-cc61a1cd1e95",
"name": "role_list",
"description": "SAML role list",
"protocol": "saml",
"attributes": {
"consent.screen.text": "${samlRoleListScopeConsentText}",
"display.on.consent.screen": "true"
},
"protocolMappers": [
{
"id": "040520c7-9dfb-4f9d-a93e-17e3267b1517",
"name": "role list",
"protocol": "saml",
"protocolMapper": "saml-role-list-mapper",
"consentRequired": false,
"config": {
"single": "false",
"attribute.nameformat": "Basic",
"attribute.name": "Role"
}
}
]
},
{
"id": "f0ff8363-c507-4113-adc0-47f6b346de26",
"name": "roles",
"description": "OpenID Connect scope for add user roles to the access token",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "false",
"display.on.consent.screen": "true",
"consent.screen.text": "${rolesScopeConsentText}"
},
"protocolMappers": [
{
"id": "13aa2234-81bf-4018-a67c-d657045eac1f",
"name": "client roles",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-client-role-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"multivalued": "true",
"user.attribute": "foo",
"access.token.claim": "true",
"claim.name": "resource_access.${client_id}.roles",
"jsonType.label": "String"
}
},
{
"id": "d0b63e0d-5543-41dc-baf6-1c6987d6a18d",
"name": "audience resolve",
"protocol": "openid-connect",
"protocolMapper": "oidc-audience-resolve-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"access.token.claim": "true"
}
},
{
"id": "38881c98-4009-412b-b924-d36f55273f3e",
"name": "realm roles",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-realm-role-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"multivalued": "true",
"user.attribute": "foo",
"access.token.claim": "true",
"claim.name": "realm_access.roles",
"jsonType.label": "String"
}
}
]
},
{
"id": "b8a70a2a-a24d-4862-ad4b-dd737b60f7ce",
"name": "microprofile-jwt",
"description": "Microprofile - JWT built-in scope",
"protocol": "openid-connect",
"attributes": {
"include.in.token.scope": "true",
"display.on.consent.screen": "false"
},
"protocolMappers": [
{
"id": "4eb888ff-b503-4506-b35c-ea0ac0ff3cd3",
"name": "groups",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-realm-role-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"multivalued": "true",
"userinfo.token.claim": "true",
"user.attribute": "foo",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "groups",
"jsonType.label": "String"
}
},
{
"id": "d39896cb-3f45-4a62-a254-f7d0eb10e60a",
"name": "upn",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"introspection.token.claim": "true",
"userinfo.token.claim": "true",
"user.attribute": "username",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "upn",
"jsonType.label": "String"
}
}
]
}
],
"defaultDefaultClientScopes": [ "role_list", "profile", "email", "roles", "web-origins", "acr" ],
"defaultOptionalClientScopes": [ "offline_access", "address", "phone", "microprofile-jwt", "weather:all" ],
"browserSecurityHeaders": {
"contentSecurityPolicyReportOnly": "",
"xContentTypeOptions": "nosniff",
"referrerPolicy": "no-referrer",
"xRobotsTag": "none",
"xFrameOptions": "SAMEORIGIN",
"contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
"xXSSProtection": "1; mode=block",
"strictTransportSecurity": "max-age=31536000; includeSubDomains"
},
"smtpServer": {},
"eventsEnabled": false,
"eventsListeners": [ "jboss-logging" ],
"enabledEventTypes": [],
"adminEventsEnabled": false,
"adminEventsDetailsEnabled": false,
"identityProviders": [],
"identityProviderMappers": [],
"components": {
"org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
{
"id": "887848c6-60f6-47ac-ae7f-62f8a5608a4b",
"name": "Trusted Hosts",
"providerId": "trusted-hosts",
"subType": "anonymous",
"subComponents": {},
"config": {
"host-sending-registration-request-must-match": [ "true" ],
"client-uris-must-match": [ "true" ]
}
},
{
"id": "4333143f-bf59-419a-99e2-2cce8a5d414a",
"name": "Consent Required",
"providerId": "consent-required",
"subType": "anonymous",
"subComponents": {},
"config": {}
},
{
"id": "1ac2db3a-57a1-4567-bc2b-80a2b0c96b71",
"name": "Max Clients Limit",
"providerId": "max-clients",
"subType": "anonymous",
"subComponents": {},
"config": {
"max-clients": [ "200" ]
}
},
{
"id": "adb4b546-6386-46e0-8ce9-80bacbba2afe",
"name": "Allowed Protocol Mapper Types",
"providerId": "allowed-protocol-mappers",
"subType": "authenticated",
"subComponents": {},
"config": {
"allowed-protocol-mapper-types": [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper" ]
}
},
{
"id": "241c5dea-68b9-4684-a816-80b08ef86bff",
"name": "Full Scope Disabled",
"providerId": "scope",
"subType": "anonymous",
"subComponents": {},
"config": {}
},
{
"id": "6b0e159c-33dc-492b-9d88-421973015466",
"name": "Allowed Protocol Mapper Types",
"providerId": "allowed-protocol-mappers",
"subType": "anonymous",
"subComponents": {},
"config": {
"allowed-protocol-mapper-types": [ "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-full-name-mapper" ]
}
},
{
"id": "730409bc-ce7e-4b64-a870-946aeba9f65b",
"name": "Allowed Client Scopes",
"providerId": "allowed-client-templates",
"subType": "anonymous",
"subComponents": {},
"config": {
"allow-default-scopes": [ "true" ]
}
},
{
"id": "0b4b8c74-20b6-4902-b971-9b97001da41e",
"name": "Allowed Client Scopes",
"providerId": "allowed-client-templates",
"subType": "authenticated",
"subComponents": {},
"config": {
"allow-default-scopes": [ "true" ]
}
}
],
"org.keycloak.keys.KeyProvider": [
{
"id": "c08db9a9-0d9d-4b56-96d5-7f2b1d4528df",
"name": "rsa-generated",
"providerId": "rsa-generated",
"subComponents": {},
"config": {
"privateKey": [ "MIIEowIBAAKCAQEAyJtAKWr1DdQmh9Nxp2LUGOrc5OA+rdXkV6+kOT21wVsIP/1bg6HekqfMySZhIxlALfegc90j0mrqkolb5s7axotTwwABwIvgxW5hHIQ4huntiZUYPUuf4m51dwyLs/GM1gSbzs9ciBKC5i4S21CQzuGp0QHpyOOn1kQZd0vYSGjpG3ewMYphJEfd60TQP74RcqASNoOaS3lU7+5SCQuiff1fSZYqYvIFmK3rcNrauTSryx6rh935ODSdYzQN0XA6g1WJK2hbBlBJJzeAj/CXXcBaw7aB1AoC7kjJ7XaYmHdC+7zIYhvNKcGtFhrMjoOVnJM9PiRMrk7ous7XAmKc6QIDAQABAoIBAC4qjm5Js1oqnfBpwJDrPVD7sfjJQ5t5azqjzQkwUrUMGF6zlZ06QhDhpY8QMlAjxkGd6JLpjE4nNVMiYeBA8Be7pjvs8zpG5qRBBf/MTP79dGFSitjGX+X6EjXi0P7JIuZ4+otybMLS8cV7ynKm/KBjzhMv28fT3oMAupSaA40MESKVD8BDR0bNQ6H3h1xrq2+81xViFsle9qcrZjJzCz/rttNi3DUct5IeJwc9Wai937L6H/BU5eBd9vQHM5raLL0iDSF5CQF2tE/j3hq8kdpRm9XRUm/0WaXOz8Il96GfSEUXLVvKnLdHu7qYbqKKBYI7B3xz8VYiHgDvBMqiBzUCgYEA9Sd/EijWpXAAaFOJk75BOu0sSjZHjoGbaLE1XWsQyM1fkFT9kxQ+8/kDiHSJal+utoEIrMWK/KdrrIjT0TXbWKCarV+ebgCt9dkTd6Or2SUku5k0TMSMoVEI2KxI6ZHvCz2Vxe8Ahbao28u8xOGRQYSs5ynvH0oBTex+RP3sv6UCgYEA0Xs55XdSn1PGazAuZYk9ZKJhCovdalYdjnJYxuSPfBgHV4CIHdhHvd/hohumMakQsnRDmJzbk/uFlqJecZtcQ/DukGylC/6dvfp6prUrVhghK+7+Bnry7zfQ9rMWslrlhf9ZTrQ8F9pssCtgAfs+Pfj0zF5DxQqFqF3wz12sJPUCgYATR5HkubV3uUEu8zLknZe/rJtJEs+501OHfjg2Ko9dW1linmx6vqLcyP6QIqoT5YZ179vgyoBNslTzcqdF0rh3VdoUPGrXN9J2fSXcyNBg+VzULA5C40oz/Y12jMYHKGTmO2el80/VNDI/Ztxnl123C1oVq+SUT1ue5zRe9KFDyQKBgBihnqsmnqZxWVFdNvdlbbyZg0OUMpLAUXVgaKPqWBzFToexa0/nEHh5DLTc/2uzb20sUo5tUzxRROHzcZt2IyEyATsmKzn/1Fh0TVuwzcmvyKa70U69wjbynzWC1VZfbcGVxtCETNSZMFJ+pylUe3sZ/N7S7rEKjbDAawJXB1jJAoGBAOZF4M9C1GLCZqt4RrF1MBI0Q+7Im45Hvr0FSck0y9xLpl9yolQREWoiCo5+WM54YMeSWu0rzBsLAjCoFpIX2cWcICsdPAnyyjIMPmuGt/uUaIWmq/ZRAsqkOW0sqxUMggjytNCtvdCyfQOcKsEHpBKrA6z+8l/3Z1RQFwan+VPs" ],
"certificate": [ "MIICpTCCAY0CBgGQcJfMUjANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtXZWF0aGVyU2hvcDAeFw0yNDA3MDEyMzE2NTRaFw0zNDA3MDEyMzE4MzRaMBYxFDASBgNVBAMMC1dlYXRoZXJTaG9wMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyJtAKWr1DdQmh9Nxp2LUGOrc5OA+rdXkV6+kOT21wVsIP/1bg6HekqfMySZhIxlALfegc90j0mrqkolb5s7axotTwwABwIvgxW5hHIQ4huntiZUYPUuf4m51dwyLs/GM1gSbzs9ciBKC5i4S21CQzuGp0QHpyOOn1kQZd0vYSGjpG3ewMYphJEfd60TQP74RcqASNoOaS3lU7+5SCQuiff1fSZYqYvIFmK3rcNrauTSryx6rh935ODSdYzQN0XA6g1WJK2hbBlBJJzeAj/CXXcBaw7aB1AoC7kjJ7XaYmHdC+7zIYhvNKcGtFhrMjoOVnJM9PiRMrk7ous7XAmKc6QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAeDhADaUkVzu1o8CvCfU9oa6hGsJa+2qFeUPQnG7HZAQ07MjQ/RZgMMOmdhspZIuaf+Yrx/My8VDphKzNtb2eNHgFVVQDy1F1jVy9z+t7xCwX3UfjtVNMp3tMmzWUEi0pckW0mq4Bz3w0+dKPw8z0K2c19dVN1NHDViqFghB+77tO8JguwTDE8fkmXjLixDCcenBCPXjxNWmhXgOMF1wKhlq1h0+SaKt/F2P/WzyoYu6tz8qVysQvv4knB/HEGjSji+DN+uJFE4RJG+B5X+vp5LHvlYKIROQ7/aSzvCjx7zrslmcTsSTL3F1k2Ox2Hz+rGIcA8sGqbj+W5+nKxRbad" ],
"priority": [ "100" ]
}
},
{
"id": "9adc7ed1-f51b-48d4-9d52-96b46abefa18",
"name": "aes-generated",
"providerId": "aes-generated",
"subComponents": {},
"config": {
"kid": [ "eb1853e7-ac8c-4e8f-8b4f-9ea28a71da76" ],
"secret": [ "Jges9iPdpfx0aivf3RUUpw" ],
"priority": [ "100" ]
}
},
{
"id": "f4b81876-91be-46f3-9050-c351cd1531af",
"name": "rsa-enc-generated",
"providerId": "rsa-enc-generated",
"subComponents": {},
"config": {
"privateKey": [ "MIIEowIBAAKCAQEAlP+NrT2KVZpdrbPoTsMO7MqeXYDeJNl7IXjY0hCb7p1iB6YLOr/lA5ryk/CIHI05HRt+AEYFac87mb51SEvAa9cHjQ00v7t6hoYV1esyRmB0Nnf8AAEq9GoZxX9nUsIMcExQ3gHkF56kidYtjQSgl5SlwgdvlsjRiDP9ZJlsWTBb+8v0OCCbQLZFl93IlTZ7QlaxXoB0dCuuLNyBpELFbc0+JeB+1P/Dw5azUKGdp3ng2K9IrtDBiMh+KicpLZeBpUlqdKqyI2WvwruL1SlqH/ymWCxseRH0Z9VZ30MfW8C5fHq3qnLQp0OWDa7Re/pRbCZPabivDkZCtuWUeAVbRwIDAQABAoIBAAoioBaKuyA7kefA9yp0Zk2BMuiVXYcQLCoIuGcBrjm7BvISP21NpFxsa9fYYsneaWYrepS2LqQV7q30oLG8RWiQhfj4TwBD1n/UGyQkDZVv9jfGTaQKcEuT9BDVK8gbXxE8f7u6UTOyHOsrYInZKLtm5yedrd+J5YboUnJHZXFjmCpuyap8zJQdczUpZeLkj4bRqEHYlM1a5vfMFpr2+k4/Nqo36CCaGzIcwtYxnC002rL7ra9MaR1fy5KHtcoYQeePuPvXu1UxBU01+W1QmIsw+KmXftdtWYAMcVFkHDs+22h3mCxRhQqcxmL1LUP9FfGzrWiX4eTduw4YOkzO7+ECgYEAx732U2G7Qdp1uXsVGE7ceFcrpl/LOTaL8eEtULBiFRdrn5LOTAptpoDPB8vYCwIQSNrBWXNqTiDubOBcL7sumBK2i4Omtzk/USuMcJmSiMcHaANa/ZNK9nqtwMACqXpIPEkpofzfgBSaRYY1KxaWLbepyLjqviADV98zOI4qY28CgYEAvvbNd+C0pi5u/EkUxhRdxwCxICfkDYjArcjPU3ZBjIyAzmJ08wU+3CDm2sgts1TX+D7MPsRLqsaM8vMB+BR1xo3FfP/nqNvjYkChACtHhvkWGVE/qf3/53NNa4lKeVz8h1iV18dvLICj+V+lvUyQPuER4cA8Kzs7dObl52V6OakCgYB5bSkvPW2aNhV1QbbsRRzQZ6XYicnAqUFgNRTYRbIKwmch5hxVq81G+G1jfu+CmamOsLX0DC7m+iwXsjk4pyFHP7ELlWgnYLz2OnQxC5tCXURKXifVmdJrjt7MG65Cm10IkS2nFVRFx8CVXWY7IIsBlfK4XHoQROPjaoP38K0iLwKBgQCho6RdkR04ANu+vllQJNMP7B0Be+KENjnpn60mF1X6kr9AcoRNZCZGC698hq5wOiOoo/ccNelafz+1MU58X00lqMD+QlojSySX+N6OlxOvQs2a1nQN/sqKbcWdfZNFURkLs0b6Y3xN7gFdxsEyj0kVgEszjBUh/rwgAoWdrP6dKQKBgD2b7GG1/TPTBfOvvE7q7xa5IlTMUbBU2yY8H6XvDgfG5KUXXFpqINTOE4OjuyVwJRwE2/GQGayfZvfa+LGkW8Hy6Iz/vaa1Brjodza/2PblM5v1t96xA0WQDime8okJN0q7ocbLfQnT0+3TVMbvCjeBtOqmMOJT3EijpAqVbR6N" ],
"certificate": [ "MIICpTCCAY0CBgGQcJfM/jANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtXZWF0aGVyU2hvcDAeFw0yNDA3MDEyMzE2NTVaFw0zNDA3MDEyMzE4MzVaMBYxFDASBgNVBAMMC1dlYXRoZXJTaG9wMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlP+NrT2KVZpdrbPoTsMO7MqeXYDeJNl7IXjY0hCb7p1iB6YLOr/lA5ryk/CIHI05HRt+AEYFac87mb51SEvAa9cHjQ00v7t6hoYV1esyRmB0Nnf8AAEq9GoZxX9nUsIMcExQ3gHkF56kidYtjQSgl5SlwgdvlsjRiDP9ZJlsWTBb+8v0OCCbQLZFl93IlTZ7QlaxXoB0dCuuLNyBpELFbc0+JeB+1P/Dw5azUKGdp3ng2K9IrtDBiMh+KicpLZeBpUlqdKqyI2WvwruL1SlqH/ymWCxseRH0Z9VZ30MfW8C5fHq3qnLQp0OWDa7Re/pRbCZPabivDkZCtuWUeAVbRwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAUIS+ce3NPCSk7iiA4vzm1hGrEq7Q+1CwE9hq/p8oKowOEVvg68tE+yzNsYw6qM+KKdzQfmiVeT8skDhNwL+5+Oxsg9dw7KW1me+g/pjiFx1eXt/rHN5aVDz7/F3QAP0G/CUF6dVNh0ggoGhwAH74iH91apmJgDUEBVzwaYCrHDJ81nWZOGZm4MF6FFvc8Kwf/+KEefL7psH5I4BqS+gRaPFWjBnABS7WkJ879gv0Q3tHE4KXF1b3eudGFrW4rG048pqNJgxAXdoDqFR5qIi9pfuE+HCmuhPv2Xq+I7S4PpUYnUM7o0Ng+1hJsRLhiG0Kmcepy7thiJJI619miVXdF" ],
"priority": [ "100" ],
"algorithm": [ "RSA-OAEP" ]
}
},
{
"id": "c962c2d9-ac19-4a91-88b3-959c6fcfc4c4",
"name": "hmac-generated-hs512",
"providerId": "hmac-generated",
"subComponents": {},
"config": {
"kid": [ "f43f7c3d-e27c-4a86-bda1-e1f9fa0b2c0b" ],
"secret": [ "FAyCBV9_zIF2oQO0XqgwCJz09iJDMKPHORhWI1ZV4OA9cLFVJCA-z4tEXq2QNU48xDMwv_z_UYIEm73nnJEypuaVwacu6N7jexaKjhqROYidQyPzXAr7QwD6Du1LaLdCAHaBo7rRP3Pl5fDmcX6K3C1Qe1OK86fkZVuD_2TX6No" ],
"priority": [ "100" ],
"algorithm": [ "HS512" ]
}
}
]
},
"internationalizationEnabled": false,
"supportedLocales": [],
"authenticationFlows": [
{
"id": "57c6972a-8262-4fdd-9a3d-6454f7e4804d",
"alias": "Account verification options",
"description": "Method with which to verity the existing account",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "idp-email-verification",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "ALTERNATIVE",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "Verify Existing Account by Re-authentication",
"userSetupAllowed": false
}
]
},
{
"id": "12219f2a-a63e-4e35-87b0-0c1fc82e9e00",
"alias": "Browser - Conditional OTP",
"description": "Flow to determine if the OTP is required for the authentication",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "conditional-user-configured",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "auth-otp-form",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "16a216e0-2305-4a26-8b3c-a1ad95ee0551",
"alias": "Direct Grant - Conditional OTP",
"description": "Flow to determine if the OTP is required for the authentication",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "conditional-user-configured",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "direct-grant-validate-otp",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "973a2638-3205-40a5-9ae1-171e862f98c2",
"alias": "First broker login - Conditional OTP",
"description": "Flow to determine if the OTP is required for the authentication",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "conditional-user-configured",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "auth-otp-form",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "d024eba2-74d6-4cd2-a149-eda663682a7b",
"alias": "Handle Existing Account",
"description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "idp-confirm-link",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "Account verification options",
"userSetupAllowed": false
}
]
},
{
"id": "37b5496c-9e09-402f-b079-9c588322f91d",
"alias": "Reset - Conditional OTP",
"description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "conditional-user-configured",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "reset-otp",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "62d51e78-668a-4d31-9369-0611a7507ed5",
"alias": "User creation or linking",
"description": "Flow for the existing/non-existing user alternatives",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticatorConfig": "create unique user config",
"authenticator": "idp-create-user-if-unique",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "ALTERNATIVE",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "Handle Existing Account",
"userSetupAllowed": false
}
]
},
{
"id": "ab6b9698-fd26-40a7-8edf-fa456a395394",
"alias": "Verify Existing Account by Re-authentication",
"description": "Reauthentication of existing account",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "idp-username-password-form",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "CONDITIONAL",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "First broker login - Conditional OTP",
"userSetupAllowed": false
}
]
},
{
"id": "74b79e04-bf44-4d84-92e7-04b753801622",
"alias": "browser",
"description": "browser based authentication",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "auth-cookie",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "auth-spnego",
"authenticatorFlow": false,
"requirement": "DISABLED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "identity-provider-redirector",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 25,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "ALTERNATIVE",
"priority": 30,
"autheticatorFlow": true,
"flowAlias": "forms",
"userSetupAllowed": false
}
]
},
{
"id": "bb15232e-9f1c-4dfd-8d10-e1d35cd1bfde",
"alias": "clients",
"description": "Base authentication for clients",
"providerId": "client-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "client-secret",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "client-jwt",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "client-secret-jwt",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 30,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "client-x509",
"authenticatorFlow": false,
"requirement": "ALTERNATIVE",
"priority": 40,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "dd3fe894-1594-40fb-949d-9986f36bd725",
"alias": "direct grant",
"description": "OpenID Connect Resource Owner Grant",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "direct-grant-validate-username",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "direct-grant-validate-password",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "CONDITIONAL",
"priority": 30,
"autheticatorFlow": true,
"flowAlias": "Direct Grant - Conditional OTP",
"userSetupAllowed": false
}
]
},
{
"id": "5c277901-3d67-470e-baf1-e47e9ab92dbd",
"alias": "docker auth",
"description": "Used by Docker clients to authenticate against the IDP",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "docker-http-basic-authenticator",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "e14e1d45-149f-4090-ad79-7c2d0c2f185c",
"alias": "first broker login",
"description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticatorConfig": "review profile config",
"authenticator": "idp-review-profile",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "User creation or linking",
"userSetupAllowed": false
}
]
},
{
"id": "aa2e5d63-a8e9-43e4-8461-994827de67f5",
"alias": "forms",
"description": "Username, password, otp and other auth forms.",
"providerId": "basic-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "auth-username-password-form",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "CONDITIONAL",
"priority": 20,
"autheticatorFlow": true,
"flowAlias": "Browser - Conditional OTP",
"userSetupAllowed": false
}
]
},
{
"id": "d88b5042-8af8-4797-9c6a-ae44a9a0fff2",
"alias": "registration",
"description": "registration flow",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "registration-page-form",
"authenticatorFlow": true,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": true,
"flowAlias": "registration form",
"userSetupAllowed": false
}
]
},
{
"id": "2a9320cb-970e-4b4d-b585-60d2299a043f",
"alias": "registration form",
"description": "registration form",
"providerId": "form-flow",
"topLevel": false,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "registration-user-creation",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "registration-password-action",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 50,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "registration-recaptcha-action",
"authenticatorFlow": false,
"requirement": "DISABLED",
"priority": 60,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "registration-terms-and-conditions",
"authenticatorFlow": false,
"requirement": "DISABLED",
"priority": 70,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
},
{
"id": "528ba840-6b22-4c32-ba17-40c99783883e",
"alias": "reset credentials",
"description": "Reset credentials for a user if they forgot their password or something",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "reset-credentials-choose-user",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "reset-credential-email",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 20,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticator": "reset-password",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 30,
"autheticatorFlow": false,
"userSetupAllowed": false
},
{
"authenticatorFlow": true,
"requirement": "CONDITIONAL",
"priority": 40,
"autheticatorFlow": true,
"flowAlias": "Reset - Conditional OTP",
"userSetupAllowed": false
}
]
},
{
"id": "bf172b2d-052a-4ce4-9084-c59e9b82bc10",
"alias": "saml ecp",
"description": "SAML ECP Profile Authentication Flow",
"providerId": "basic-flow",
"topLevel": true,
"builtIn": true,
"authenticationExecutions": [
{
"authenticator": "http-basic-authenticator",
"authenticatorFlow": false,
"requirement": "REQUIRED",
"priority": 10,
"autheticatorFlow": false,
"userSetupAllowed": false
}
]
}
],
"authenticatorConfig": [
{
"id": "796c70f7-6391-45ed-aafa-4ed82c84d14e",
"alias": "create unique user config",
"config": {
"require.password.update.after.registration": "false"
}
},
{
"id": "e007b422-2050-43af-b132-10ea16d92f5c",
"alias": "review profile config",
"config": {
"update.profile.on.first.login": "missing"
}
}
],
"requiredActions": [
{
"alias": "CONFIGURE_TOTP",
"name": "Configure OTP",
"providerId": "CONFIGURE_TOTP",
"enabled": true,
"defaultAction": false,
"priority": 10,
"config": {}
},
{
"alias": "TERMS_AND_CONDITIONS",
"name": "Terms and Conditions",
"providerId": "TERMS_AND_CONDITIONS",
"enabled": false,
"defaultAction": false,
"priority": 20,
"config": {}
},
{
"alias": "UPDATE_PASSWORD",
"name": "Update Password",
"providerId": "UPDATE_PASSWORD",
"enabled": true,
"defaultAction": false,
"priority": 30,
"config": {}
},
{
"alias": "UPDATE_PROFILE",
"name": "Update Profile",
"providerId": "UPDATE_PROFILE",
"enabled": true,
"defaultAction": false,
"priority": 40,
"config": {}
},
{
"alias": "VERIFY_EMAIL",
"name": "Verify Email",
"providerId": "VERIFY_EMAIL",
"enabled": true,
"defaultAction": false,
"priority": 50,
"config": {}
},
{
"alias": "delete_account",
"name": "Delete Account",
"providerId": "delete_account",
"enabled": false,
"defaultAction": false,
"priority": 60,
"config": {}
},
{
"alias": "webauthn-register",
"name": "Webauthn Register",
"providerId": "webauthn-register",
"enabled": true,
"defaultAction": false,
"priority": 70,
"config": {}
},
{
"alias": "webauthn-register-passwordless",
"name": "Webauthn Register Passwordless",
"providerId": "webauthn-register-passwordless",
"enabled": true,
"defaultAction": false,
"priority": 80,
"config": {}
},
{
"alias": "VERIFY_PROFILE",
"name": "Verify Profile",
"providerId": "VERIFY_PROFILE",
"enabled": true,
"defaultAction": false,
"priority": 90,
"config": {}
},
{
"alias": "delete_credential",
"name": "Delete Credential",
"providerId": "delete_credential",
"enabled": true,
"defaultAction": false,
"priority": 100,
"config": {}
},
{
"alias": "update_user_locale",
"name": "Update User Locale",
"providerId": "update_user_locale",
"enabled": true,
"defaultAction": false,
"priority": 1000,
"config": {}
}
],
"browserFlow": "browser",
"registrationFlow": "registration",
"directGrantFlow": "direct grant",
"resetCredentialsFlow": "reset credentials",
"clientAuthenticationFlow": "clients",
"dockerAuthenticationFlow": "docker auth",
"firstBrokerLoginFlow": "first broker login",
"attributes": {
"cibaBackchannelTokenDeliveryMode": "poll",
"cibaExpiresIn": "120",
"cibaAuthRequestedUserHint": "login_hint",
"oauth2DeviceCodeLifespan": "600",
"clientOfflineSessionMaxLifespan": "0",
"oauth2DevicePollingInterval": "5",
"clientSessionIdleTimeout": "0",
"parRequestUriLifespan": "60",
"clientSessionMaxLifespan": "0",
"clientOfflineSessionIdleTimeout": "0",
"cibaInterval": "5",
"realmReusableOtpCode": "false"
},
"keycloakVersion": "24.0.5",
"userManagedAccessAllowed": false,
"clientProfiles": {
"profiles": []
},
"clientPolicies": {
"policies": []
}
}
Durchführung von Integrationsgesundheitsprüfungen
Die Keycloak-Hostingintegration unterstützt derzeit keine Integritätsprüfungen und fügt sie auch nicht automatisch hinzu.
Client Integration
Um mit der .NET AspireKeycloakclient-Integration zu beginnen, installieren Sie die 📦Aspire.Keycloak. Die Authentifizierung NuGet-Paket im projekt client-verbrauchend, d. h. das Projekt für die Anwendung, die die Keycloakclientverwendet. Die Keycloakclient Integration registriert JwtBearer- und OpenId Connect-Authentifizierungs-Handler im DI-Container, um eine Verbindung mit einem Keycloakherzustellen.
dotnet add package Aspire.Keycloak.Authentication
JWT-Bearer-Authentifizierung hinzufügen
Rufen Sie in der Program.cs Datei Ihres ASP.NET Core-API-Projekts die AddKeycloakJwtBearer Erweiterungsmethode auf, um die JwtBearer-Authentifizierung mit einem Verbindungsnamen, einem Bereich und allen erforderlichen JWT Bearer-Optionen hinzuzufügen:
builder.Services.AddAuthentication()
.AddKeycloakJwtBearer(
serviceName: "keycloak",
realm: "api",
options =>
{
options.Audience = "store.api";
});
Sie können viele weitere Optionen über den Action<JwtBearerOptions> configureOptions
-Delegat festlegen.
Beispiel für die JWT-Bearer-Authentifizierung
Um die JWT-Bearer-Authentifizierung weiter zu veranschaulichen, siehe das folgende Beispiel:
var builder = WebApplication.CreateBuilder(args);
// Add service defaults & Aspire client integrations.
builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddProblemDetails();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.AddAuthentication()
.AddKeycloakJwtBearer(
serviceName: "keycloak",
realm: "WeatherShop",
configureOptions: options =>
{
options.RequireHttpsMetadata = false;
options.Audience = "weather.api";
});
builder.Services.AddAuthorizationBuilder();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseExceptionHandler();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.RequireAuthorization();
app.MapDefaultEndpoints();
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Die vorangehende ASP.NET Core Minimal-API Program
Klasse veranschaulicht:
- Hinzufügen von Authentifizierungsdiensten zum DI-Container mit der AddAuthentication-API.
- Hinzufügen der JWT-Bearerauthentifizierung mit der AddKeycloakJwtBearer-API und Konfigurieren:
- Die
serviceName
alskeycloak
. - Die
realm
alsWeatherShop
. - Die
options
, derenAudience
aufweather.api
festgelegt ist, und legtRequireHttpsMetadata
auffalse
fest.
- Die
- Fügt dem DI-Container mit der AddAuthorizationBuilder-API Autorisierungsdienste hinzu.
- Ruft die RequireAuthorization-API auf, um eine Autorisierung für den
/weatherforecast
Endpunkt zu erfordern.
Ein vollständiges Arbeitsbeispiel finden Sie unter .NET Aspire Spielfeld: Keycloak Integration.
Hinzufügen der OpenId Connect-Authentifizierung
Rufen Sie in der Program.cs-Datei Ihres API-verbrauchenden Projekts (z. B. Blazor) die AddKeycloakOpenIdConnect Erweiterungsmethode auf, um die OpenId Connect-Authentifizierung hinzuzufügen, indem Sie einen Verbindungsnamen, einen Bereich und alle erforderlichen OpenId Connect-Optionen verwenden:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddKeycloakOpenIdConnect(
serviceName: "keycloak",
realm: "api",
options =>
{
options.ClientId = "StoreWeb";
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("store:all");
});
Sie können viele weitere Optionen über den Action<OpenIdConnectOptions>? configureOptions
-Delegat festlegen.
OpenId Connect-Authentifizierung (Beispiel)
Um die OpenId Connect-Authentifizierung weiter zu veranschaulichen, betrachten Sie das folgende Beispiel:
using System.IdentityModel.Tokens.Jwt;
using AspireApp.Web;
using AspireApp.Web.Components;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
var builder = WebApplication.CreateBuilder(args);
// Add service defaults & Aspire client integrations.
builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddOutputCache();
builder.Services.AddHttpContextAccessor()
.AddTransient<AuthorizationHandler>();
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// This URL uses "https+http://" to indicate HTTPS is preferred over HTTP.
// Learn more about service discovery scheme resolution at https://aka.ms/dotnet/sdschemes.
client.BaseAddress = new("https+http://apiservice");
})
.AddHttpMessageHandler<AuthorizationHandler>();
var oidcScheme = OpenIdConnectDefaults.AuthenticationScheme;
builder.Services.AddAuthentication(oidcScheme)
.AddKeycloakOpenIdConnect("keycloak", realm: "WeatherShop", oidcScheme, options =>
{
options.ClientId = "WeatherWeb";
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("weather:all");
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
options.SaveTokens = true;
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
builder.Services.AddCascadingAuthenticationState();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.UseOutputCache();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.MapLoginAndLogout();
app.Run();
Die vorangehende ASP.NET CoreBlazorProgram
Klasse:
- Fügt den
HttpContextAccessor
dem DI-Container mit der AddHttpContextAccessor-API hinzu. - Fügt dem DI-Container mit der AddTransient<TService>(IServiceCollection)-API einen benutzerdefinierten
AuthorizationHandler
als vorübergehenden Dienst hinzu. - Fügt dem
WeatherApiClient
Dienst mit der AddHttpClient<TClient>(IServiceCollection)-API eine HttpClient hinzu und konfiguriert die Basisadresse mit Dienstermittlung Semantik, die zumapiservice
aufgelöst wird.- Verkettet einen Aufruf der AddHttpMessageHandler-API, um eine
AuthorizationHandler
zurHttpClient
-Pipeline hinzuzufügen.
- Verkettet einen Aufruf der AddHttpMessageHandler-API, um eine
- Fügt dem DI-Container Authentifizierungsdienste hinzu, wobei die AddAuthentication-API das OpenId Connect-Standardauthentifizierungsschema übergibt.
- Ruft AddKeycloakOpenIdConnect auf und konfiguriert die
serviceName
alskeycloak
, dierealm
alsWeatherShop
und dasoptions
-Objekt mit verschiedenen Einstellungen. - Fügt der Blazor-App mit der AddCascadingAuthenticationState-API gestaffelte Authentifizierungszustände hinzu.
Der letzte Hinweis ist die Erweiterungsmethode MapLoginAndLogout
, die Anmelde- und Abmelderouten zur App Blazor hinzufügt. Dies ist wie folgt definiert:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.HttpResults;
namespace AspireApp.Web;
internal static class LoginLogoutEndpointRouteBuilderExtensions
{
internal static IEndpointConventionBuilder MapLoginAndLogout(
this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("authentication");
group.MapGet(pattern: "/login", OnLogin).AllowAnonymous();
group.MapPost(pattern: "/logout", OnLogout);
return group;
}
static ChallengeHttpResult OnLogin() =>
TypedResults.Challenge(properties: new AuthenticationProperties
{
RedirectUri = "/"
});
static SignOutHttpResult OnLogout() =>
TypedResults.SignOut(properties: new AuthenticationProperties
{
RedirectUri = "/"
},
[
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme
]);
}
Der vorangehende Code:
- Ordnet eine Gruppe der Route
authentication
zu und ordnet zwei Endpunkte den Routenlogin
undlogout
zu.- Ordnet eine
GET
-Anforderung der/login
-Route zu, deren Handler dieOnLogin
-Methode ist – dies ist ein anonymer Endpunkt. - Ordnet eine
GET
-Anforderung der/logout
-Route zu, deren Handler dieOnLogout
-Methode ist.
- Ordnet eine
Die AuthorizationHandler
ist ein benutzerdefinierter Handler, der das Bearer
-Token zur HttpClient
-Anforderung hinzufügt. Der Handler ist wie folgt definiert:
using Microsoft.AspNetCore.Authentication;
using System.Net.Http.Headers;
namespace AspireApp.Web;
public class AuthorizationHandler(IHttpContextAccessor httpContextAccessor)
: DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var httpContext = httpContextAccessor.HttpContext ??
throw new InvalidOperationException("""
No HttpContext available from the IHttpContextAccessor.
""");
var accessToken = await httpContext.GetTokenAsync("access_token");
if (!string.IsNullOrWhiteSpace(accessToken))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}
return await base.SendAsync(request, cancellationToken);
}
}
Der vorangehende Code:
- Ist eine Unterklasse der Klasse DelegatingHandler.
- Fügt den
IHttpContextAccessor
Dienst in den primären Konstruktor ein. - Überschreibt die
SendAsync
-Methode, um dasBearer
-Token zurHttpClient
-Anforderung hinzuzufügen.- Die
access_token
wird aus demHttpContext
abgerufen und zur KopfzeileAuthorization
hinzugefügt.
- Die
Um den Authentifizierungsfluss zu visualisieren, ziehen Sie das folgende Sequenzdiagramm in Betracht:
Ein vollständiges Arbeitsbeispiel finden Sie unter .NET Aspire-Spielplatz: Keycloak-Integration.