diff --git a/deploy/oauth/README.md b/deploy/oauth/README.md
new file mode 100644
index 000000000..6c824b292
--- /dev/null
+++ b/deploy/oauth/README.md
@@ -0,0 +1,43 @@
+## Oauth2-Proxy
+
+Used to locally, manually test te behaviour of auth-reverse-proxies like ALB.
+
+Based on the suggested docker images from the main [oauth2-proxy environment](https://github.com/oauth2-proxy/oauth2-proxy/tree/master/contrib/local-environment)
+
+### Pre-requisites
+
+Add this to your /etc/hosts (uncommented)
+
+```
+127.0.0.1 keycloak
+127.0.0.1 oauth2-proxy
+```
+
+Credentials | admin/password
+Email | admin@datavisyn.io
+
+# Configuration
+
+Frontend env (common env in dev, different in prod) via webpack dotenv
+
+## LOGOUT_URL
+
+The logout url consists of multiple redirects. First we need to perform the oauth2 proxy sign out via calling `/oauth2/sign_out`.
+This sign out procedure deletes the oauth2 cookie and redirects to the open id connect provider via `rd=...`. The redirect url must be an encoded url.
+In our local test case, the redirect url will then point to keycloak's openid-connect logout: `auth/realms/{realm}/protocol/openid-connect/logout`. This ensures that the oidc provider also knows that the user should be logged out to prevent automatic redirects to the app with a valid cookie.
+
+```
+?rd=http://keycloak:9080/auth/realms/master/protocol/openid-connect/logout?redirect_uri=http://localhost:4180
+```
+
+- REFRESH_URL
+
+Backend env
+
+```env
+VISYN_CORE__SECURITY__STORE__OAUTH2_SECURITY_STORE__ENABLE=true
+VISYN_CORE__SECURITY__STORE__OAUTH2_SECURITY_STORE__ACCESS_TOKEN_HEADER_NAME=x-forwarded-access-token
+VISYN_CORE__SECURITY__STORE__OAUTH2_SECURITY_STORE__COOKIE_NAME=_oauth2_proxy
+VISYN_CORE__SECURITY__STORE__OAUTH2_SECURITY_STORE__SIGNOUT_URL=http://localhost:4180/oauth2/sign_out?rd=http%3A%2F%2Fkeycloak%3A9080%2Fauth%2Frealms%2Fmaster%2Fprotocol%2Fopenid-connect%2Flogout%3Fredirect_uri%3Dhttp%3A%2F%2Flocalhost%3A4180
+
+```
diff --git a/deploy/oauth/docker-compose.yaml b/deploy/oauth/docker-compose.yaml
new file mode 100644
index 000000000..bc89472e9
--- /dev/null
+++ b/deploy/oauth/docker-compose.yaml
@@ -0,0 +1,39 @@
+# Simplified variant of https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment/docker-compose-keycloak.yaml
+version: '3.0'
+services:
+ oauth2-proxy:
+ container_name: oauth2-proxy
+ image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0
+ command: --config /oauth2-proxy.cfg
+ hostname: oauth2-proxy
+ volumes:
+ - './oauth2-proxy.cfg:/oauth2-proxy.cfg'
+ restart: unless-stopped
+ depends_on:
+ - keycloak
+ network_mode: host
+ # required for oauth2-proxy.cfg - upstreams localhost, as the frontend isn't available inside docker
+
+ keycloak:
+ container_name: keycloak
+ image: jboss/keycloak:10.0.0
+ hostname: keycloak
+ command:
+ [
+ '-Djboss.socket.binding.port-offset=1000',
+ '-Dkeycloak.migration.action=import',
+ '-Dkeycloak.migration.provider=dir',
+ '-Dkeycloak.migration.dir=/realm-config',
+ '-Dkeycloak.migration.strategy=IGNORE_EXISTING',
+ ]
+ volumes:
+ - ./keycloak:/realm-config
+ environment:
+ KEYCLOAK_USER: admin
+ KEYCLOAK_PASSWORD: password
+ ports:
+ - 9080:9080/tcp
+# this docker image REALLY doesn't like to run in network-mode host
+# requires this in your /etc/hosts (uncommented)
+# 127.0.0.1 keycloak
+# 127.0.0.1 oauth2-proxy
diff --git a/deploy/oauth/keycloak/master-realm.json b/deploy/oauth/keycloak/master-realm.json
new file mode 100644
index 000000000..7c1b3d986
--- /dev/null
+++ b/deploy/oauth/keycloak/master-realm.json
@@ -0,0 +1,1686 @@
+{
+ "id" : "master",
+ "realm" : "master",
+ "displayName" : "Keycloak",
+ "displayNameHtml" : "
Keycloak
",
+ "notBefore" : 0,
+ "revokeRefreshToken" : false,
+ "refreshTokenMaxReuse" : 0,
+ "accessTokenLifespan" : 36000,
+ "accessTokenLifespanForImplicitFlow" : 36000,
+ "ssoSessionIdleTimeout" : 36000,
+ "ssoSessionMaxLifespan" : 36000,
+ "ssoSessionIdleTimeoutRememberMe" : 0,
+ "ssoSessionMaxLifespanRememberMe" : 0,
+ "offlineSessionIdleTimeout" : 2592000,
+ "offlineSessionMaxLifespanEnabled" : false,
+ "offlineSessionMaxLifespan" : 5184000,
+ "clientSessionIdleTimeout" : 0,
+ "clientSessionMaxLifespan" : 0,
+ "accessCodeLifespan" : 36000,
+ "accessCodeLifespanUserAction" : 36000,
+ "accessCodeLifespanLogin" : 36000,
+ "actionTokenGeneratedByAdminLifespan" : 43200,
+ "actionTokenGeneratedByUserLifespan" : 36000,
+ "enabled" : true,
+ "sslRequired" : "external",
+ "registrationAllowed" : false,
+ "registrationEmailAsUsername" : false,
+ "rememberMe" : false,
+ "verifyEmail" : false,
+ "loginWithEmailAllowed" : true,
+ "duplicateEmailsAllowed" : false,
+ "resetPasswordAllowed" : false,
+ "editUsernameAllowed" : false,
+ "bruteForceProtected" : false,
+ "permanentLockout" : false,
+ "maxFailureWaitSeconds" : 900,
+ "minimumQuickLoginWaitSeconds" : 60,
+ "waitIncrementSeconds" : 60,
+ "quickLoginCheckMilliSeconds" : 1000,
+ "maxDeltaTimeSeconds" : 43200,
+ "failureFactor" : 30,
+ "roles" : {
+ "realm" : [ {
+ "id" : "32626c92-4327-40f1-b318-76a6b5c7eee5",
+ "name" : "offline_access",
+ "description" : "${role_offline-access}",
+ "composite" : false,
+ "clientRole" : false,
+ "containerId" : "master",
+ "attributes" : { }
+ }, {
+ "id" : "e36da570-7ae0-4323-8b39-73eb92ce722f",
+ "name" : "admin",
+ "description" : "${role_admin}",
+ "composite" : true,
+ "composites" : {
+ "realm" : [ "create-realm" ],
+ "client" : {
+ "master-realm" : [ "query-groups", "create-client", "query-realms", "view-authorization", "view-realm", "manage-clients", "query-users", "manage-realm", "view-events", "manage-events", "view-identity-providers", "view-users", "manage-identity-providers", "manage-authorization", "manage-users", "view-clients", "query-clients", "impersonation" ]
+ }
+ },
+ "clientRole" : false,
+ "containerId" : "master",
+ "attributes" : { }
+ }, {
+ "id" : "71aca46c-6fcf-4456-ba87-6374e70108a2",
+ "name" : "uma_authorization",
+ "description" : "${role_uma_authorization}",
+ "composite" : false,
+ "clientRole" : false,
+ "containerId" : "master",
+ "attributes" : { }
+ }, {
+ "id" : "6ca3fee8-1a3f-4068-a311-6e81223a884b",
+ "name" : "create-realm",
+ "description" : "${role_create-realm}",
+ "composite" : false,
+ "clientRole" : false,
+ "containerId" : "master",
+ "attributes" : { }
+ } ],
+ "client" : {
+ "oauth2-proxy" : [ ],
+ "security-admin-console" : [ ],
+ "admin-cli" : [ ],
+ "account-console" : [ ],
+ "broker" : [ {
+ "id" : "2cc5e40c-0a28-4c09-85eb-20cd47ac1351",
+ "name" : "read-token",
+ "description" : "${role_read-token}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "380985f1-61c7-4940-93ae-7a09458071ca",
+ "attributes" : { }
+ } ],
+ "master-realm" : [ {
+ "id" : "a8271c2c-6437-4ca5-ae83-49ea5fe1318d",
+ "name" : "query-groups",
+ "description" : "${role_query-groups}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "5a7cb1ae-7dac-486b-bf7b-4d7fbc5adb31",
+ "name" : "create-client",
+ "description" : "${role_create-client}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "a9e6a2fa-c31b-4959-bf8a-a46fcc9c65ec",
+ "name" : "view-authorization",
+ "description" : "${role_view-authorization}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "1cef34e3-569a-4d2b-ba5c-aafe5c7ab423",
+ "name" : "query-realms",
+ "description" : "${role_query-realms}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "efc46075-30cd-4600-aa92-2ae4a171d0c2",
+ "name" : "view-realm",
+ "description" : "${role_view-realm}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "9ffacaf0-afc6-49e9-8708-ef35ac40f3f8",
+ "name" : "manage-clients",
+ "description" : "${role_manage-clients}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "90662091-b3bc-4ae4-83c9-a4f53e7e9eeb",
+ "name" : "query-users",
+ "description" : "${role_query-users}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "9a5fbc9d-6fae-4155-86f6-72fd399aa126",
+ "name" : "manage-realm",
+ "description" : "${role_manage-realm}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "03f46127-9436-477d-8c7f-58569f45237c",
+ "name" : "view-events",
+ "description" : "${role_view-events}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "f10eaea2-90ab-4310-9d5f-8d986564d061",
+ "name" : "view-identity-providers",
+ "description" : "${role_view-identity-providers}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "2403e038-2cf7-4b06-b5cb-33a417a00d8d",
+ "name" : "manage-events",
+ "description" : "${role_manage-events}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "677d057b-66f8-4163-9948-95fdbd06dfdc",
+ "name" : "view-users",
+ "description" : "${role_view-users}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "master-realm" : [ "query-groups", "query-users" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "dc140fa6-bf2c-49f2-b8c9-fc34ef8a2c63",
+ "name" : "manage-identity-providers",
+ "description" : "${role_manage-identity-providers}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "155bf234-4895-4855-95c2-a460518f57e8",
+ "name" : "manage-authorization",
+ "description" : "${role_manage-authorization}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "5441ec71-3eac-4696-9e68-0de54fbdde98",
+ "name" : "manage-users",
+ "description" : "${role_manage-users}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "2db0f052-cb91-4170-81fd-107756b162f7",
+ "name" : "view-clients",
+ "description" : "${role_view-clients}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "master-realm" : [ "query-clients" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "e1d7f235-8bf2-40b8-be49-49aca70a5088",
+ "name" : "query-clients",
+ "description" : "${role_query-clients}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ }, {
+ "id" : "e743f66a-2f56-4b97-b34b-33f06ff1e739",
+ "name" : "impersonation",
+ "description" : "${role_impersonation}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "attributes" : { }
+ } ],
+ "account" : [ {
+ "id" : "64d8f532-839e-4386-b2eb-fe8848b0a9de",
+ "name" : "manage-consent",
+ "description" : "${role_manage-consent}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "account" : [ "view-consent" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ }, {
+ "id" : "3ec22748-960f-4f96-a43e-50f54a02dc23",
+ "name" : "view-profile",
+ "description" : "${role_view-profile}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ }, {
+ "id" : "177d18e4-46b0-4ea3-8b70-327486ce5bb2",
+ "name" : "view-applications",
+ "description" : "${role_view-applications}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ }, {
+ "id" : "703643d6-0542-4e27-9737-7c442925c18c",
+ "name" : "manage-account-links",
+ "description" : "${role_manage-account-links}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ }, {
+ "id" : "c64f9f66-d762-4337-8833-cf31c316e8a7",
+ "name" : "view-consent",
+ "description" : "${role_view-consent}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ }, {
+ "id" : "611f568b-0fdd-4d2e-ba34-03136cd486c4",
+ "name" : "manage-account",
+ "description" : "${role_manage-account}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "account" : [ "manage-account-links" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "attributes" : { }
+ } ]
+ }
+ },
+ "groups" : [ ],
+ "defaultRoles" : [ "offline_access", "uma_authorization" ],
+ "requiredCredentials" : [ "password" ],
+ "otpPolicyType" : "totp",
+ "otpPolicyAlgorithm" : "HmacSHA1",
+ "otpPolicyInitialCounter" : 0,
+ "otpPolicyDigits" : 6,
+ "otpPolicyLookAheadWindow" : 1,
+ "otpPolicyPeriod" : 30,
+ "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ],
+ "webAuthnPolicyRpEntityName" : "keycloak",
+ "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+ "webAuthnPolicyRpId" : "",
+ "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+ "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+ "webAuthnPolicyRequireResidentKey" : "not specified",
+ "webAuthnPolicyUserVerificationRequirement" : "not specified",
+ "webAuthnPolicyCreateTimeout" : 0,
+ "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+ "webAuthnPolicyAcceptableAaguids" : [ ],
+ "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+ "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+ "webAuthnPolicyPasswordlessRpId" : "",
+ "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+ "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+ "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+ "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+ "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+ "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+ "scopeMappings" : [ {
+ "clientScope" : "offline_access",
+ "roles" : [ "offline_access" ]
+ } ],
+ "clientScopeMappings" : {
+ "account" : [ {
+ "client" : "account-console",
+ "roles" : [ "manage-account" ]
+ } ]
+ },
+ "clients" : [ {
+ "id" : "a367038f-fe01-4459-9f91-7ad0cf498533",
+ "clientId" : "account",
+ "name" : "${client_account}",
+ "rootUrl" : "${authBaseUrl}",
+ "baseUrl" : "/realms/master/account/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "0896a464-da81-4454-bee9-b56bdbad9e7f",
+ "defaultRoles" : [ "view-profile", "manage-account" ],
+ "redirectUris" : [ "/realms/master/account/*" ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "72f75604-1e21-407c-b967-790aafd11534",
+ "clientId" : "account-console",
+ "name" : "${client_account-console}",
+ "rootUrl" : "${authBaseUrl}",
+ "baseUrl" : "/realms/master/account/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "91f85142-ee18-4e30-9949-e5acb701bdee",
+ "redirectUris" : [ "/realms/master/account/*" ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "pkce.code.challenge.method" : "S256"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "protocolMappers" : [ {
+ "id" : "2772c101-0dba-49b7-9627-5aaddc666939",
+ "name" : "audience resolve",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-audience-resolve-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ } ],
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "b13fd0de-3be0-4a08-bc5d-d1de34421b1a",
+ "clientId" : "admin-cli",
+ "name" : "${client_admin-cli}",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "4640af2e-b4a6-44eb-85ec-6278a62a4f01",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : false,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : true,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "380985f1-61c7-4940-93ae-7a09458071ca",
+ "clientId" : "broker",
+ "name" : "${client_broker}",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "65d2ba2b-bcae-49ff-9f56-77c818f55930",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "7174c175-1887-4e57-b95b-969fe040deff",
+ "clientId" : "master-realm",
+ "name" : "master Realm",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "40f73851-a94c-4091-90de-aeee8ca1acf8",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : true,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : true,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ },
+ {
+ "id": "0493c7c6-6e20-49ea-9acb-627c0b52d400",
+ "clientId": "oauth2-proxy",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "72341b6d-7065-4518-a0e4-50ee15025608",
+ "redirectUris": [
+ "http://localhost:4180/oauth2/callback",
+ "http://localhost:4180"
+ ],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "saml.assertion.signature": "false",
+ "saml.force.post.binding": "false",
+ "saml.multivalued.roles": "false",
+ "saml.encrypt": "false",
+ "saml.server.signature": "false",
+ "saml.server.signature.keyinfo.ext": "false",
+ "exclude.session.state.from.auth.response": "false",
+ "saml_force_name_id_format": "false",
+ "saml.client.signature": "false",
+ "tls.client.certificate.bound.access.tokens": "false",
+ "saml.authnstatement": "false",
+ "display.on.consent.screen": "false",
+ "saml.onetimeuse.condition": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": -1,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ }, {
+ "id" : "2a3ad1fd-a30d-4b72-89c4-bed12f178338",
+ "clientId" : "security-admin-console",
+ "name" : "${client_security-admin-console}",
+ "rootUrl" : "${authAdminUrl}",
+ "baseUrl" : "/admin/master/console/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "b234b7aa-8417-410f-b3fd-c57434d3aa4a",
+ "redirectUris" : [ "/admin/master/console/*" ],
+ "webOrigins" : [ "+" ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "pkce.code.challenge.method" : "S256"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "protocolMappers" : [ {
+ "id" : "5885b0d3-a917-4b52-8380-f37d0754a2ef",
+ "name" : "locale",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "locale",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "locale",
+ "jsonType.label" : "String"
+ }
+ } ],
+ "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ } ],
+ "clientScopes" : [ {
+ "id" : "47ea3b67-4f0c-4c7e-8ac6-a33a3d655894",
+ "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" : "4be0ca19-0ec7-4cc1-b263-845ea539ff12",
+ "name" : "address",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-address-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute.formatted" : "formatted",
+ "user.attribute.country" : "country",
+ "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" : "aba72e57-540f-4825-95b7-2d143be028cc",
+ "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" : "7fe82724-5748-4b6d-9708-a028f5d3b970",
+ "name" : "email verified",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "emailVerified",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "email_verified",
+ "jsonType.label" : "boolean"
+ }
+ }, {
+ "id" : "e42f334e-cfae-44a0-905d-c3ef215feaae",
+ "name" : "email",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "email",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "email",
+ "jsonType.label" : "String"
+ }
+ } ]
+ }, {
+ "id" : "ec765598-bd71-4318-86c3-b3f81a41c99e",
+ "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" : "90694036-4014-4672-a2c8-c68319e9308a",
+ "name" : "upn",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "upn",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "f7b0fcc0-6139-4158-ac45-34fd9a58a5ef",
+ "name" : "groups",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "multivalued" : "true",
+ "user.attribute" : "foo",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "groups",
+ "jsonType.label" : "String"
+ }
+ } ]
+ }, {
+ "id" : "8a09267b-3634-4a9c-baab-6f2fb4137347",
+ "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" : "3a48c5dd-33a8-4be0-9d2e-30fd7f98363a",
+ "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" : "5427d1b4-ba79-412a-b23c-da640a98980c",
+ "name" : "phone number",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "phoneNumber",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "phone_number",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "31d4a53f-6503-40e8-bd9d-79a7c46c4fbe",
+ "name" : "phone number verified",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "phoneNumberVerified",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "phone_number_verified",
+ "jsonType.label" : "boolean"
+ }
+ } ]
+ }, {
+ "id" : "5921a9e9-7fec-4471-95e3-dd96eebdec58",
+ "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" : "4fa92092-ee0d-4dc7-a63b-1e3b02d35ebb",
+ "name" : "zoneinfo",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "zoneinfo",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "zoneinfo",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "1a5cc2e2-c983-4150-8583-23a7f5c826bf",
+ "name" : "family name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "lastName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "family_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "67931f77-722a-492d-b581-a953e26b7d44",
+ "name" : "full name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-full-name-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "userinfo.token.claim" : "true"
+ }
+ }, {
+ "id" : "10f6ac36-3a63-4e1c-ac69-c095588f5967",
+ "name" : "locale",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "locale",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "locale",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "205d9dce-b6c8-4b1d-9c9c-fa24788651cf",
+ "name" : "picture",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "picture",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "picture",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "638216c8-ea8c-40e3-9429-771e9278920e",
+ "name" : "gender",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "gender",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "gender",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "39c17eae-8ea7-422c-ae21-b8876bf12184",
+ "name" : "birthdate",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "birthdate",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "birthdate",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "01c559cf-94f2-46ad-b965-3b2e1db1a2a6",
+ "name" : "updated at",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "updatedAt",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "updated_at",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "1693b5ab-28eb-485d-835d-2ae070ccb3ba",
+ "name" : "profile",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "profile",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "profile",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "a0e08332-954c-46d2-9795-56eb31132580",
+ "name" : "given name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "firstName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "given_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "cea0cd9c-d085-4d19-acc3-4bb41c891b68",
+ "name" : "nickname",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "nickname",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "nickname",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "3122097d-4cba-46c2-8b3b-5d87a4cc605e",
+ "name" : "middle name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "middleName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "middle_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "a3b97897-d913-4e0a-a4cf-033ce78f7d24",
+ "name" : "username",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "preferred_username",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "a44eeb9d-410d-49c5-b0e0-5d84787627ad",
+ "name" : "website",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "website",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "website",
+ "jsonType.label" : "String"
+ }
+ } ]
+ }, {
+ "id" : "651408a7-6704-4198-a60f-988821b633ea",
+ "name" : "role_list",
+ "description" : "SAML role list",
+ "protocol" : "saml",
+ "attributes" : {
+ "consent.screen.text" : "${samlRoleListScopeConsentText}",
+ "display.on.consent.screen" : "true"
+ },
+ "protocolMappers" : [ {
+ "id" : "a8c56c7b-ccbc-4b01-8df5-3ecb6328755f",
+ "name" : "role list",
+ "protocol" : "saml",
+ "protocolMapper" : "saml-role-list-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "single" : "false",
+ "attribute.nameformat" : "Basic",
+ "attribute.name" : "Role"
+ }
+ } ]
+ }, {
+ "id" : "13ec0fd3-e64a-4d6f-9be7-c8760f2c9d6b",
+ "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" : "75e741f8-dcd5-49d2-815e-8604ec1d08a1",
+ "name" : "realm roles",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute" : "foo",
+ "access.token.claim" : "true",
+ "claim.name" : "realm_access.roles",
+ "jsonType.label" : "String",
+ "multivalued" : "true"
+ }
+ }, {
+ "id" : "06a2d506-4996-4a33-8c43-2cf64af6a630",
+ "name" : "client roles",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-client-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute" : "foo",
+ "access.token.claim" : "true",
+ "claim.name" : "resource_access.${client_id}.roles",
+ "jsonType.label" : "String",
+ "multivalued" : "true"
+ }
+ }, {
+ "id" : "3c3470df-d414-4e1c-87fc-3fb3cea34b8d",
+ "name" : "audience resolve",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-audience-resolve-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ } ]
+ }, {
+ "id" : "d85aba25-c74b-49e3-9ccb-77b4bb16efa5",
+ "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" : "86b3f64f-1525-4500-bcbc-9b889b25f995",
+ "name" : "allowed web origins",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-allowed-origins-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ } ]
+ } ],
+ "defaultDefaultClientScopes" : [ "roles", "profile", "role_list", "email", "web-origins" ],
+ "defaultOptionalClientScopes" : [ "phone", "address", "offline_access", "microprofile-jwt" ],
+ "browserSecurityHeaders" : {
+ "contentSecurityPolicyReportOnly" : "",
+ "xContentTypeOptions" : "nosniff",
+ "xRobotsTag" : "none",
+ "xFrameOptions" : "SAMEORIGIN",
+ "xXSSProtection" : "1; mode=block",
+ "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+ "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+ },
+ "smtpServer" : { },
+ "eventsEnabled" : false,
+ "eventsListeners" : [ "jboss-logging" ],
+ "enabledEventTypes" : [ ],
+ "adminEventsEnabled" : false,
+ "adminEventsDetailsEnabled" : false,
+ "components" : {
+ "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+ "id" : "59048b39-ad0f-4d12-8c52-7cfc2c43278a",
+ "name" : "Allowed Protocol Mapper Types",
+ "providerId" : "allowed-protocol-mappers",
+ "subType" : "authenticated",
+ "subComponents" : { },
+ "config" : {
+ "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper" ]
+ }
+ }, {
+ "id" : "760559a6-a59f-4175-9ac5-6f3612e20129",
+ "name" : "Trusted Hosts",
+ "providerId" : "trusted-hosts",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "host-sending-registration-request-must-match" : [ "true" ],
+ "client-uris-must-match" : [ "true" ]
+ }
+ }, {
+ "id" : "24f4cb42-76bd-499e-812a-4e0d270c9e13",
+ "name" : "Full Scope Disabled",
+ "providerId" : "scope",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : { }
+ }, {
+ "id" : "abbfc599-480a-44ef-8e33-73a83eaab166",
+ "name" : "Allowed Protocol Mapper Types",
+ "providerId" : "allowed-protocol-mappers",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper" ]
+ }
+ }, {
+ "id" : "3c6450f0-4521-402b-a247-c8165854b1fa",
+ "name" : "Allowed Client Scopes",
+ "providerId" : "allowed-client-templates",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "allow-default-scopes" : [ "true" ]
+ }
+ }, {
+ "id" : "d9b64399-744b-498e-9d35-f68b1582bd7d",
+ "name" : "Consent Required",
+ "providerId" : "consent-required",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : { }
+ }, {
+ "id" : "22f15f1f-3116-4348-a1e5-fc0d7576452a",
+ "name" : "Max Clients Limit",
+ "providerId" : "max-clients",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "max-clients" : [ "200" ]
+ }
+ }, {
+ "id" : "4ad7b291-ddbb-4674-8c3d-ab8fd76d4168",
+ "name" : "Allowed Client Scopes",
+ "providerId" : "allowed-client-templates",
+ "subType" : "authenticated",
+ "subComponents" : { },
+ "config" : {
+ "allow-default-scopes" : [ "true" ]
+ }
+ } ],
+ "org.keycloak.keys.KeyProvider" : [ {
+ "id" : "f71cc325-9907-4d27-a0e6-88fca7450e5e",
+ "name" : "aes-generated",
+ "providerId" : "aes-generated",
+ "subComponents" : { },
+ "config" : {
+ "kid" : [ "6c7d982e-372f-49c6-a4f3-5c451fb85eca" ],
+ "secret" : [ "yH6M3W7aOgh2_cKJ0srWbw" ],
+ "priority" : [ "100" ]
+ }
+ }, {
+ "id" : "7b50d0ab-dda5-4624-aa42-b4b397724ce1",
+ "name" : "hmac-generated",
+ "providerId" : "hmac-generated",
+ "subComponents" : { },
+ "config" : {
+ "kid" : [ "587f0fb5-845d-4b45-87a0-84145092aaef" ],
+ "secret" : [ "PuH8Lxh9GeNfGJRDk34SWIlBDdrJpC3U3SfcxqqQtlIf2DBzRKUu8VbDVrmMN5b5CoPsJhrQ2SVb-iE9Lzsb3A" ],
+ "priority" : [ "100" ],
+ "algorithm" : [ "HS256" ]
+ }
+ }, {
+ "id" : "547c1c71-9f97-4e12-801b-ed5c2cc61bba",
+ "name" : "rsa-generated",
+ "providerId" : "rsa-generated",
+ "subComponents" : { },
+ "config" : {
+ "privateKey" : [ "MIIEowIBAAKCAQEAjdo2HZ5ruNnIbkSeAfFYpbPvJw3vtz/VuKJerC4mUXYd7qRMhs3VLJZ3mFyeCuO8W81vkGrFiC9KQnX2lHj2dtA/RWEJw5bpz+JdOFr5pvXg0lQ0sa+hro9afWDygTU4FmLsEi5z98847TbH178RT6n7+JVqZ9jYU9rSpwVTC8E/4yxSuStmhGCcAkZ6dGhHNBdvGUgwxKYj7dYLRJiI+nilIdKuxPzxI/YZxZnXBHDdbNXJgDymTQPut99OnBxeZbH38CJ1MNo3VdV1fzOMGUHe+vn/EOD5E+pXC8PwvJnWU+XHUTFVZeyIXehh3pYLUsq/6bZ1MYsEaFIhznOkwwIDAQABAoIBAHB+64fVyUxRurhoRn737fuLlU/9p2xGfbHtYvNdrhnQeLB3MBGAT10K/1Gfsd6k+Q49AAsiAgGcr2HBt4nL3HohcOwOpvWsS0UIGjHFRFP6jw9+pEN+K9UJ7xObvPZnRFHMpbdNi76tYlINrbMV3h61ihR8OmSc/gKSeZjnihK5OkaNnlqGRaBM/koI+iAxUHuJPnBLBZmD4T8eIfE4S2TvUeVeQogI9Muvnb9tIPJ5XyP9iXWLdRjnek/+wTdxHHZuo06Tc0bMjRaTHiF6K9ntOM2EmQb6bS2J47zgzRLNFE22BWH7RJq659EzElkOn0C0k7dWDTur/3Lpx1+zxJECgYEA8t+J3J+9oGTFmY2VPH05Yr/R/iVDOyIOlO1CmgonOQ3KPhbfNBB3aTAJP20LOZChN4JoWuiZJg4UwzXOeY9DvdDkPO0YLlSjPAIwJNk+xcxFcp5hqMUul2db+cgEY8zp0Wg9kFOq3JmJjK4+1+fgsVnOB+B08ZYI6bZzsUVKzucCgYEAlYTrsxs6fQua0cvZNQPYNZzwF3LVwPBl/ntkdRBE3HGyZeCAhIj7e9pAUusCPsQJaCmW2UEmywD/aIxGrBkojzTKItshM3PN1PYKL8W0Zq+H67uF5KfdvsbabZWHfP/LGCpoKF8Ov7JVPPqGrZ03Z2SheeLZAtNeHN4OB1u9i8UCgYATkS7qN3Rvl67T0DRVy0D0U7/3Wckw2m2SUgsrneXLEvFYTz9sUmdMcjJMidx9pslWT4tYx6SPDFNf5tXbtU8f29SHlBJ+qRL9oq9+SIJmLS7rLRdxIXG/gPRIC3VPFRNBa8SJ/DOn0jbivqcRffz8TN/sgojpbc0KB0kK3ypHwQKBgCKVCcb1R0PgyUA4+9YNO5a647UotFPZxl1jwMpqpuKt0WtKz67X2AK/ah1DidNmmB5lcCRzsztE0c4mk7n+X6kvtoj1UeqKoFLfTV/bRGxzsOZPCxrl0J3tdFvgN+QrbZf7Rvf/dHPWFWzzLO8+66+YUNjWJQdIR/45Rdlh2KdZAoGBAMfF3ir+fe3KdQ6hAf9QyrLxJ5l+GO+IgtxXGbon7eeJBIZHHdMeDy4pC7DMcI214BmIntbyY+xS+gI3oM26EJUVmrZ6tkyIDFsCHm9rcXG9ogvffzQWM1Wqzm27hR/3s+EPWW9AOcIimiFV1UPp/mLjnrCuq58V2aJS/TT14oLe" ],
+ "certificate" : [ "MIICmzCCAYMCBgFygL/j4DANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjAwNjA0MTkxMDU4WhcNMzAwNjA0MTkxMjM4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCN2jYdnmu42chuRJ4B8Vils+8nDe+3P9W4ol6sLiZRdh3upEyGzdUslneYXJ4K47xbzW+QasWIL0pCdfaUePZ20D9FYQnDlunP4l04Wvmm9eDSVDSxr6Guj1p9YPKBNTgWYuwSLnP3zzjtNsfXvxFPqfv4lWpn2NhT2tKnBVMLwT/jLFK5K2aEYJwCRnp0aEc0F28ZSDDEpiPt1gtEmIj6eKUh0q7E/PEj9hnFmdcEcN1s1cmAPKZNA+63306cHF5lsffwInUw2jdV1XV/M4wZQd76+f8Q4PkT6lcLw/C8mdZT5cdRMVVl7Ihd6GHelgtSyr/ptnUxiwRoUiHOc6TDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIAqydMYxa51kNEyfXyR2kStlglE4LDeLBLHDABeBPE0eN2awoH/mw3kXS4OA/C0e3c7bAwViOzOVERGeUNiBvP5rL1Amuu97nwFcxhkTaJH4ZwCGkxceaIo9LNDpAEesqHLQSdplFXIA4TbEFoKMem4k31KVU7i9/rUesrSRmxLptIOK7LLvRMYiY/t7tdAvoZAtoliuQlFKQywEuxXQrCkcoVEAARABWGt0rsWC2xK0tVxHRIrENwvMp/aUYd17sZ0403aaS9dlvfQ63ExnaHd+++RJtPku8P220Tw27YVmFAwzJgS0aUpEaDsgRNz6OMSyxEg/n7eKK08aU3szwQ=" ],
+ "priority" : [ "100" ]
+ }
+ } ]
+ },
+ "internationalizationEnabled" : false,
+ "supportedLocales" : [ ],
+ "authenticationFlows" : [ {
+ "id" : "3253f9b7-905d-4458-ad8a-8ada5e16d195",
+ "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",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "flowAlias" : "Verify Existing Account by Re-authentication",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "75bd854e-ab99-46f1-90ed-a8bfc1559558",
+ "alias" : "Authentication Options",
+ "description" : "Authentication options.",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "basic-auth",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "basic-auth-otp",
+ "requirement" : "DISABLED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-spnego",
+ "requirement" : "DISABLED",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "9b0e6cce-62c5-4fb6-a48d-e07c950e38c3",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-otp-form",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "1c26fd14-ac06-4dc1-bdd8-8c34c1b41720",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "direct-grant-validate-otp",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "254f7549-51ec-4565-a736-35c07b6e25f0",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-otp-form",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "b2413da8-3de9-4bfe-b77e-643fd1964c8f",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "Account verification options",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "f8392bfb-8dce-4a16-8af1-b2a4d1a0a273",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-otp",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "fb69c297-b26e-44fa-aabd-d7b40eec3cd3",
+ "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",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "flowAlias" : "Handle Existing Account",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "de3a41a9-7018-4931-9c4d-d04f9501b2ce",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 20,
+ "flowAlias" : "First broker login - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "6526b0d1-b48e-46c6-bb08-11ebcf458def",
+ "alias" : "browser",
+ "description" : "browser based authentication",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "auth-cookie",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-spnego",
+ "requirement" : "DISABLED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "identity-provider-redirector",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 25,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 30,
+ "flowAlias" : "forms",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "92a653ba-8f2d-4283-8354-ca55f9d89181",
+ "alias" : "clients",
+ "description" : "Base authentication for clients",
+ "providerId" : "client-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "client-secret",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-jwt",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-secret-jwt",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-x509",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 40,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "e365be39-78db-46f0-b2e8-4e7001c2f5d0",
+ "alias" : "direct grant",
+ "description" : "OpenID Connect Resource Owner Grant",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "direct-grant-validate-username",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "direct-grant-validate-password",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 30,
+ "flowAlias" : "Direct Grant - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "dd61caf5-a40f-48b7-9e8c-a1f3b67041dd",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "7a055643-62e1-4ac1-b126-9a8d6c299635",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "User creation or linking",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "fe8bc7ee-6e8f-436e-8336-c60fcd350843",
+ "alias" : "forms",
+ "description" : "Username, password, otp and other auth forms.",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "auth-username-password-form",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 20,
+ "flowAlias" : "Browser - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "3646f08e-ab70-415b-a701-6ed2e2d214c9",
+ "alias" : "http challenge",
+ "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "no-cookie-redirect",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "Authentication Options",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "04176530-0972-47ad-83df-19d8534caac2",
+ "alias" : "registration",
+ "description" : "registration flow",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "registration-page-form",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "flowAlias" : "registration form",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "fa0ed569-6746-439e-b07e-89f7ed918c07",
+ "alias" : "registration form",
+ "description" : "registration form",
+ "providerId" : "form-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "registration-user-creation",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-profile-action",
+ "requirement" : "REQUIRED",
+ "priority" : 40,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-password-action",
+ "requirement" : "REQUIRED",
+ "priority" : 50,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-recaptcha-action",
+ "requirement" : "DISABLED",
+ "priority" : 60,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "03680917-28f3-4ccd-bdf6-4a516f7c0018",
+ "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",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-credential-email",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-password",
+ "requirement" : "REQUIRED",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 40,
+ "flowAlias" : "Reset - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "19a9d9aa-2d2b-4701-807f-c384ab921c7e",
+ "alias" : "saml ecp",
+ "description" : "SAML ECP Profile Authentication Flow",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "http-basic-authenticator",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ } ],
+ "authenticatorConfig" : [ {
+ "id" : "534f01f4-45b3-43a0-91d1-238860cc126d",
+ "alias" : "create unique user config",
+ "config" : {
+ "require.password.update.after.registration" : "false"
+ }
+ }, {
+ "id" : "65bb9337-9633-4a21-8f6f-1d4129f664ac",
+ "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" : "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",
+ "attributes" : { },
+ "keycloakVersion" : "10.0.0",
+ "userManagedAccessAllowed" : false
+}
+
diff --git a/deploy/oauth/keycloak/master-users-0.json b/deploy/oauth/keycloak/master-users-0.json
new file mode 100644
index 000000000..69415e7f0
--- /dev/null
+++ b/deploy/oauth/keycloak/master-users-0.json
@@ -0,0 +1,31 @@
+{
+ "realm": "master",
+ "users": [
+ {
+ "id": "admin@datavisyn.io",
+ "createdTimestamp": 1591297959169,
+ "username": "admin",
+ "email": "admin@datavisyn.io",
+ "enabled": true,
+ "totp": false,
+ "emailVerified": true,
+ "credentials": [
+ {
+ "id": "a1a06ecd-fdc0-4e67-92cd-2da22d724e32",
+ "type": "password",
+ "createdDate": 1591297959315,
+ "secretData": "{\"value\":\"6rt5zuqHVHopvd0FTFE0CYadXTtzY0mDY2BrqnNQGS51/7DfMJeGgj0roNnGMGvDv30imErNmiSOYl+cL9jiIA==\",\"salt\":\"LI0kqr09JB7J9wvr2Hxzzg==\"}",
+ "credentialData": "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+ }
+ ],
+ "disableableCredentialTypes": [],
+ "requiredActions": [],
+ "realmRoles": ["offline_access", "admin", "uma_authorization"],
+ "clientRoles": {
+ "account": ["view-profile", "manage-account"]
+ },
+ "notBefore": 0,
+ "groups": []
+ }
+ ]
+}
diff --git a/deploy/oauth/oauth2-proxy.cfg b/deploy/oauth/oauth2-proxy.cfg
new file mode 100644
index 000000000..731e022a6
--- /dev/null
+++ b/deploy/oauth/oauth2-proxy.cfg
@@ -0,0 +1,25 @@
+# modified variant of oauth2-proxy-keycloak.cfg
+# https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment/oauth2-proxy-keycloak.cfg
+http_address="0.0.0.0:4180"
+cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
+email_domains=["*"]
+cookie_secure="false"
+upstreams="http://localhost:8080"
+redirect_url="http://localhost:4180/oauth2/callback"
+
+# keycloak provider
+client_secret="72341b6d-7065-4518-a0e4-50ee15025608"
+client_id="oauth2-proxy"
+whitelist_domains=["keycloak:9080"]
+
+oidc_issuer_url="http://keycloak:9080/auth/realms/master"
+provider="oidc"
+provider_display_name="Keycloak"
+
+# custom config, other than default
+# https://github.com/oauth2-proxy/oauth2-proxy/issues/843#issuecomment-717212451
+# Header: Authorization: Bearer {jwt}
+pass_authorization_header=true
+# Header: X-Forwarded-Access-Token
+pass_access_token=true
+skip_provider_button = true
diff --git a/package.json b/package.json
index cc0f7477c..038b62801 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "visyn_core",
"description": "Core repository for datavisyn applications.",
- "version": "3.1.1-SNAPSHOT",
+ "version": "4.0.1-SNAPSHOT",
"author": {
"name": "datavisyn GmbH",
"email": "contact@datavisyn.io",
diff --git a/requirements.txt b/requirements.txt
index 4d8d05c68..7067d4b0c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,30 +1,35 @@
# a2wsgi==1.6.0 # This WSIGMiddleware is not compatible with starlette_context
-alembic==1.9.4
-cachetools==5.3.0
-fastapi[all]==0.92.0
+alembic==1.11.1
+cachetools==5.3.1
+fastapi==0.101.1
Flask[async]>=2.1.0,<=2.2.2
json-cfg==0.4.2
-marshmallow-sqlalchemy>=0.26.0,<=0.28.1
-marshmallow==3.19.0
-openpyxl==3.0.9
-opentelemetry-api==1.18.0
-opentelemetry-exporter-otlp==1.18.0
+openpyxl==3.1.2
+opentelemetry-api==1.19.0
+opentelemetry-exporter-otlp==1.19.0
opentelemetry-exporter-prometheus==1.12.0rc1
-opentelemetry-instrumentation-fastapi==0.39b0
-opentelemetry-instrumentation-httpx==0.39b0
-opentelemetry-instrumentation-logging==0.39b0
-opentelemetry-instrumentation-requests==0.39b0
-opentelemetry-instrumentation-sqlalchemy==0.39b0
-opentelemetry-instrumentation-system-metrics==0.39b0
-opentelemetry-sdk==1.18.0
-psycopg==3.1.8
-psycopg2==2.9.5
-pydantic==1.10.5
-pyjwt[crypto]==2.6.0
-pytest-postgresql==4.1.1
+opentelemetry-instrumentation-fastapi==0.40b0
+opentelemetry-instrumentation-httpx==0.40b0
+opentelemetry-instrumentation-logging==0.40b0
+opentelemetry-instrumentation-requests==0.40b0
+opentelemetry-instrumentation-sqlalchemy==0.40b0
+opentelemetry-instrumentation-system-metrics==0.40b0
+opentelemetry-sdk==1.19.0
+psycopg==3.1.9
+psycopg2==2.9.6
+pydantic==1.10.11
+pyjwt[crypto]==2.8.0
+pytest-postgresql==5.0.0
python-dateutil==2.8.2
-python-multipart==0.0.5
-requests==2.28.2
-SQLAlchemy>=1.4.40,<=1.4.46
+python-multipart==0.0.6
+requests==2.31.0
+SQLAlchemy>=1.4.40,<=1.4.49
starlette-context==0.3.6
-uvicorn[standard]==0.20.0
+uvicorn[standard]==0.23.1
+# Extras from fastapi[all], which we can't install because it requires pydantic v2: https://github.com/tiangolo/fastapi/blob/f7e3559bd5997f831fb9b02bef9c767a50facbc3/pyproject.toml#L57-L67
+httpx>=0.23.0
+jinja2>=2.11.2
+itsdangerous>=1.1.0
+pyyaml>=5.3.1
+ujson>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0
+orjson>=3.2.1
diff --git a/src/app/login/VisynLoginMenu.tsx b/src/app/login/VisynLoginMenu.tsx
index 7e49736f7..014527a34 100644
--- a/src/app/login/VisynLoginMenu.tsx
+++ b/src/app/login/VisynLoginMenu.tsx
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
import { Alert, Modal, Stack, Title, Center, Divider, Container, LoadingOverlay, Anchor } from '@mantine/core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCircleExclamation } from '@fortawesome/free-solid-svg-icons/faCircleExclamation';
-import { appContext } from '../../base/AppContext';
import { userSession } from '../../security/UserSession';
import { LoginUtils } from '../../security/LoginUtils';
import { SessionWatcher } from '../../security/watcher';
@@ -13,7 +12,7 @@ import { DefaultLoginForm, UserStoreUIMap } from './UserStoreUIMap';
export function VisynLoginMenu({ watch = false }: { watch?: boolean }) {
const { appName, user } = useVisynAppContext();
const [show, setShow] = useState(false);
- const [error, setError] = useState(null);
+ const [error, setError] = useState(null);
React.useEffect(() => {
if (watch) {
@@ -73,6 +72,7 @@ export function VisynLoginMenu({ watch = false }: { watch?: boolean }) {
component="button"
type="button"
onClick={() => {
+ setError(null);
retryGetStores();
}}
>
diff --git a/src/utils/fromNow.ts b/src/utils/fromNow.ts
index 8d97b69f8..681656893 100644
--- a/src/utils/fromNow.ts
+++ b/src/utils/fromNow.ts
@@ -1,4 +1,4 @@
-const formatter = new Intl.RelativeTimeFormat(undefined, {
+const formatter = new Intl.RelativeTimeFormat('en', {
numeric: 'auto',
});
diff --git a/visyn_core/dbmanager.py b/visyn_core/dbmanager.py
index 7dc284ab5..f2e68e001 100644
--- a/visyn_core/dbmanager.py
+++ b/visyn_core/dbmanager.py
@@ -3,7 +3,7 @@
from fastapi import FastAPI
from sqlalchemy.engine import Engine
-from sqlalchemy.orm import Session
+from sqlalchemy.orm import Session, sessionmaker
from . import manager
from .dbview import DBConnector
@@ -17,8 +17,8 @@ class DBManager:
def __init__(self):
self.connectors: dict[str, DBConnector] = {}
self._plugins = {}
- self._engines = {}
- self._sessionmakers = {}
+ self._engines: dict[str, Engine] = {}
+ self._sessionmakers: dict[Engine, sessionmaker] = {}
def init_app(self, app: FastAPI):
app.add_middleware(CloseWebSessionsMiddleware)
diff --git a/visyn_core/rdkit/img_api.py b/visyn_core/rdkit/img_api.py
index e29dcea3b..bdb3e746f 100644
--- a/visyn_core/rdkit/img_api.py
+++ b/visyn_core/rdkit/img_api.py
@@ -13,7 +13,7 @@
from .util.draw import draw, draw_similarity
from .util.molecule import aligned, maximum_common_substructure_query_mol
-app = APIRouter(prefix="/api/rdkit", tags=["images"])
+app = APIRouter(prefix="/api/rdkit", tags=["RDKit"])
@app.get("/", response_class=SvgResponse)
diff --git a/visyn_core/security/store/alb_security_store.py b/visyn_core/security/store/alb_security_store.py
index 064752931..ca9490429 100644
--- a/visyn_core/security/store/alb_security_store.py
+++ b/visyn_core/security/store/alb_security_store.py
@@ -27,7 +27,7 @@ def __init__(
self,
cookie_name: str | None,
signout_url: str | None,
- email_token_field: str,
+ email_token_field: str | list[str],
audience: str | list[str] | None,
issuer: str | None,
decode_options: dict[str, Any] | None,
@@ -36,7 +36,7 @@ def __init__(
):
self.cookie_name = cookie_name
self.signout_url = signout_url
- self.email_token_field = email_token_field
+ self.email_token_fields = [email_token_field] if isinstance(email_token_field, str) else email_token_field
self.audience = audience
self.issuer = issuer
self.decode_options = decode_options
@@ -66,9 +66,15 @@ def load_from_request(self, req: Request):
algorithms=self.decode_algorithms,
)
+ # Go through all the fields we want to check for the user id
+ id = next((user.get(field, None) for field in self.email_token_fields if user.get(field, None)), None)
+ if not id:
+ _log.error(f"No {self.email_token_fields} matched in token, possible fields: {user.keys()}")
+ return None
+
# Create new user from given attributes
return User(
- id=user[self.email_token_field],
+ id=id,
roles=user.get("roles", []),
oauth2_access_token=req.headers["X-Amzn-Oidc-Accesstoken"],
)
diff --git a/visyn_core/security/store/oauth2_security_store.py b/visyn_core/security/store/oauth2_security_store.py
index d80a7e708..031151a62 100644
--- a/visyn_core/security/store/oauth2_security_store.py
+++ b/visyn_core/security/store/oauth2_security_store.py
@@ -13,9 +13,10 @@
class OAuth2SecurityStore(BaseStore):
ui = "AutoLoginForm"
- def __init__(self, cookie_name: str | None, signout_url: str | None):
+ def __init__(self, cookie_name: str | None, signout_url: str | None, email_token_field: str | list[str]):
self.cookie_name = cookie_name
self.signout_url: str | None = signout_url
+ self.email_token_fields = [email_token_field] if isinstance(email_token_field, str) else email_token_field
def load_from_request(self, req: Request):
token_field = manager.settings.visyn_core.security.store.oauth2_security_store.access_token_header_name
@@ -25,10 +26,16 @@ def load_from_request(self, req: Request):
if access_token:
# Try to decode the oidc data jwt
user = jwt.decode(access_token, options={"verify_signature": False})
+
+ # Go through all the fields we want to check for the user id
+ id = next((user.get(field, None) for field in self.email_token_fields if user.get(field, None)), None)
+ if not id:
+ _log.error(f"No {self.email_token_fields} matched in token, possible fields: {user.keys()}")
+ return None
+
# Create new user from given attributes
- email = user[manager.settings.visyn_core.security.store.oauth2_security_store.email_token_field]
return User(
- id=email,
+ id=id,
roles=[],
oauth2_access_token=access_token,
)
@@ -60,6 +67,7 @@ def create():
return OAuth2SecurityStore(
manager.settings.visyn_core.security.store.oauth2_security_store.cookie_name,
manager.settings.visyn_core.security.store.oauth2_security_store.signout_url,
+ manager.settings.visyn_core.security.store.oauth2_security_store.email_token_field,
)
return None
diff --git a/visyn_core/server/visyn_server.py b/visyn_core/server/visyn_server.py
index 3b0a0b97c..0dee41743 100644
--- a/visyn_core/server/visyn_server.py
+++ b/visyn_core/server/visyn_server.py
@@ -4,7 +4,6 @@
import threading
from typing import Any
-import anyio
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
from pydantic import create_model
@@ -164,8 +163,15 @@ def filter(self, record: logging.LogRecord) -> bool:
async def change_anyio_total_tokens():
# FastAPI uses anyio threads to handle sync endpoint concurrently.
# This is a workaround to increase the number of threads to 100, as the default is only 40.
- limiter = anyio.to_thread.current_default_thread_limiter()
- limiter.total_tokens = manager.settings.visyn_core.total_anyio_tokens
+ try:
+ from anyio import to_thread
+
+ limiter = to_thread.current_default_thread_limiter()
+ limiter.total_tokens = manager.settings.visyn_core.total_anyio_tokens
+ except Exception as e:
+ _log.exception(
+ f"Could not set the total number of anyio tokens to {manager.settings.visyn_core.total_anyio_tokens}. Error: {e}"
+ )
if manager.settings.visyn_core.cypress:
_log.info("Cypress mode is enabled. This should only be used in a Cypress testing environment or CI.")
diff --git a/visyn_core/settings/model.py b/visyn_core/settings/model.py
index 0b4ef743e..8e8ddfe71 100644
--- a/visyn_core/settings/model.py
+++ b/visyn_core/settings/model.py
@@ -1,8 +1,8 @@
import contextlib
-import json
from typing import Any, Literal
-from pydantic import AnyHttpUrl, BaseModel, BaseSettings, Extra, Field, validator
+from pydantic import AnyHttpUrl, BaseConfig, BaseModel, BaseSettings, Extra, Field
+from pydantic.env_settings import EnvSettingsSource, SettingsSourceCallable
from .constants import default_logging_dict
@@ -44,7 +44,7 @@ class AlbSecurityStoreSettings(BaseModel):
enable: bool = False
cookie_name: str | None = None
signout_url: str | None = None
- email_token_field: str = "email"
+ email_token_field: str | list[str] = ["email"]
"""
Field in the JWT token that contains the email address of the user.
"""
@@ -76,7 +76,7 @@ class OAuth2SecurityStoreSettings(BaseModel):
cookie_name: str | None = None
signout_url: str | None = None
access_token_header_name: str = "X-Forwarded-Access-Token"
- email_token_field: str = "email"
+ email_token_field: str | list[str] = ["email"]
class NoSecurityStoreSettings(BaseModel):
@@ -110,15 +110,6 @@ class BaseExporterTelemetrySettings(BaseModel):
timeout: int | None = None
kwargs: dict[str, Any] = {}
- @validator("headers", pre=True)
- def json_decode_headers(cls, v): # NOQA N805
- # Manually parse JSON strings if they are coming from the env via `VISYN_CORE__...='{"...": ...}'`.
- # See https://github.com/pydantic/pydantic/issues/831 for details.
- if isinstance(v, str):
- with contextlib.suppress(ValueError):
- return json.loads(v)
- return v
-
class MetricsExporterTelemetrySettings(BaseExporterTelemetrySettings):
pass
@@ -211,15 +202,6 @@ class VisynCoreSettings(BaseModel):
client_config: dict[str, Any] | None = None
"""Client config to be loaded via /api/v1/visyn/clientConfig"""
- @validator("client_config", pre=True)
- def json_decode_client_config(cls, v): # NOQA N805
- # Manually parse JSON strings if they are coming from the env via `VISYN_CORE__CLIENT_CONFIG='{"...": ...}'`.
- # See https://github.com/pydantic/pydantic/issues/831 for details.
- if isinstance(v, str):
- with contextlib.suppress(ValueError):
- return json.loads(v)
- return v
-
class GlobalSettings(BaseSettings):
env: Literal["development", "production"] = "production"
@@ -255,6 +237,54 @@ def get_nested(self, key: str, default: Any = None) -> Any | None:
dic = dic.get(key, None) if dic else None
return dic if dic is not None else default
- class Config:
+ class Config(BaseConfig):
extra = Extra.allow
env_nested_delimiter = "__"
+
+ @classmethod
+ def customise_sources(
+ cls,
+ init_settings: SettingsSourceCallable,
+ env_settings: EnvSettingsSource,
+ file_secret_settings: SettingsSourceCallable,
+ ) -> tuple[SettingsSourceCallable, ...]:
+ class EnvSettingsSourceWithJSON(EnvSettingsSource):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ """
+ String vars that end with this suffix are not converted to JSON.
+ """
+ self.as_string_suffix = "_as_string"
+
+ def explode_env_vars(self, *args, **kwargs) -> dict[str, Any]:
+ """
+ This may be hacky, but it allows us to load JSON strings from the environment variables, even for deeply nested models.
+ The original explode_env_vars simply stores the values as strings, and does not load them as JSON.
+ Here, we patch it and iterate over all values, and try to load them as JSON.
+ TODO: This may have one negative side effect: what if my value is typed as a string, but we now convert it to a dict?
+ You can suffix the variable with `_as_string` to prevent this.
+ """
+ exploded = super().explode_env_vars(*args, **kwargs)
+
+ def str_to_dict(d: dict[str, Any]):
+ for k in list(d.keys()):
+ if isinstance(d[k], dict):
+ str_to_dict(d[k])
+ elif isinstance(d[k], str):
+ if k.lower().endswith(self.as_string_suffix):
+ # If the value ends with the suffix, add the string value without the suffix to the dict.
+ d[k.lower().removesuffix(self.as_string_suffix)] = d[k]
+ else:
+ # Otherwise, try to load the value as JSON.
+ with contextlib.suppress(ValueError):
+ d[k] = cls.json_loads(d[k])
+ return d
+
+ return str_to_dict(exploded)
+
+ return (
+ init_settings,
+ # Instead of the default EnvSettingsSource, use our custom one.
+ EnvSettingsSourceWithJSON(**{s: getattr(env_settings, s) for s in env_settings.__slots__}),
+ file_secret_settings,
+ )
diff --git a/visyn_core/tests/test_security_login.py b/visyn_core/tests/test_security_login.py
index 55383e55e..2ae0cae7a 100644
--- a/visyn_core/tests/test_security_login.py
+++ b/visyn_core/tests/test_security_login.py
@@ -120,6 +120,7 @@ def test_jwt_token_location(client: TestClient):
def test_alb_security_store(client: TestClient):
# Add some basic configuration
manager.settings.visyn_core.security.store.alb_security_store.enable = True
+ manager.settings.visyn_core.security.store.alb_security_store.email_token_field = ["field1", "field2", "email"]
manager.settings.visyn_core.security.store.alb_security_store.decode_options = {"verify_signature": False}
manager.settings.visyn_core.security.store.alb_security_store.cookie_name = "TestCookie"
manager.settings.visyn_core.security.store.alb_security_store.signout_url = "http://localhost/logout"
@@ -150,6 +151,10 @@ def test_alb_security_store(client: TestClient):
assert response.status_code == 200
assert response.json()["redirect"] == "http://localhost/logout"
+ # Test if we are not logged in if we use invalid fields
+ store.email_token_fields = ["field1", "field2"]
+ assert client.get("/loggedinas", headers=headers).json() == '"not_yet_logged_in"'
+
def test_oauth2_security_store(client: TestClient):
# Add some basic configuration
diff --git a/visyn_core/tests/test_settings.py b/visyn_core/tests/test_settings.py
index 0795dfcd1..b52d8f6d3 100644
--- a/visyn_core/tests/test_settings.py
+++ b/visyn_core/tests/test_settings.py
@@ -14,8 +14,12 @@ def test_env_substitution():
assert settings.secret_key != "Custom_Secret_Key"
assert settings.visyn_core.security.store.alb_security_store.enable != True # NOQA: E712
+ assert settings.visyn_core.security.store.alb_security_store.cookie_name is None
+ assert settings.visyn_core.security.store.alb_security_store.email_token_field == ["email"]
+ assert settings.visyn_core.security.store.oauth2_security_store.email_token_field == ["email"]
assert settings.visyn_core.logging["version"] == 1
assert settings.visyn_core.logging["root"]["level"] == "INFO"
+ assert settings.visyn_core.client_config is None
with mock.patch.dict(
os.environ,
@@ -23,10 +27,18 @@ def test_env_substitution():
# Basic top-level key substitution
"SECRET_KEY": "Custom_Secret_Key",
# Deeply nested key substitution of properly typed model (includes automatic typecast)
- "visyn_core__SECURITY__STORE__ALB_SECURITY_STORE__ENABLE": "True",
+ "VISYN_CORE__SECURITY__STORE__ALB_SECURITY_STORE__ENABLE": "True",
+ # Deeply nested key substitution without automatic dict conversion
+ "VISYN_CORE__SECURITY__STORE__ALB_SECURITY_STORE__COOKIE_NAME_AS_STRING": '{"my": "dict"}',
+ # Deeply nested key substitution with automatic dict conversion
+ "VISYN_CORE__SECURITY__STORE__ALB_SECURITY_STORE__EMAIL_TOKEN_FIELD": '["field1", "email"]',
+ "VISYN_CORE__SECURITY__STORE__OAUTH2_SECURITY_STORE__EMAIL_TOKEN_FIELD": "field1",
# Deeply nested key substitution of model typed via Dict (does not include automatic typecast)
- "visyn_core__LOGGING__VERSION": "2",
- "visyn_core__LOGGING__ROOT__LEVEL": "DEBUG",
+ "VISYN_CORE__LOGGING__VERSION": "2",
+ "VISYN_CORE__LOGGING__VERSION_AS_STRING_AS_STRING": "2",
+ "VISYN_CORE__LOGGING__ROOT__LEVEL": "DEBUG",
+ # Load dict types from JSON strings. Important: it must be a valid JSON, i.e. no \" escaping or so. Use single quotes to enclose the variable.
+ "VISYN_CORE__CLIENT_CONFIG": '{"demo_from_function": true, "demo_from_class": true}',
},
clear=True,
):
@@ -34,14 +46,19 @@ def test_env_substitution():
assert env_settings.secret_key == "Custom_Secret_Key"
assert env_settings.visyn_core.security.store.alb_security_store.enable == True # NOQA: E712
- assert env_settings.visyn_core.logging["version"] == "2" # Note that this is a string, as it cannot infer the type of Dict
+ assert env_settings.visyn_core.security.store.alb_security_store.cookie_name == '{"my": "dict"}'
+ assert env_settings.visyn_core.security.store.alb_security_store.email_token_field == ["field1", "email"]
+ assert env_settings.visyn_core.security.store.oauth2_security_store.email_token_field == "field1"
+ assert env_settings.visyn_core.logging["version"] == 2
assert env_settings.visyn_core.logging["root"]["level"] == "DEBUG"
+ assert env_settings.visyn_core.client_config == {"demo_from_function": True, "demo_from_class": True}
assert env_settings.get_nested("secret_key") == "Custom_Secret_Key"
assert env_settings.get_nested("visyn_core.security.store.alb_security_store.enable") == True # NOQA: E712
- assert (
- env_settings.get_nested("visyn_core.logging.version") == "2"
- ) # Note that this is a string, as it cannot infer the type of Dict
+ assert env_settings.get_nested("visyn_core.logging.version") == 2
+ # Both variants as string are preserved, in case a real setting ends with the suffix
+ assert env_settings.get_nested("visyn_core.logging.version_as_string") == "2"
+ assert env_settings.get_nested("visyn_core.logging.version_as_string_as_string") == "2"
assert env_settings.get_nested("visyn_core.logging.root.level") == "DEBUG"