diff --git a/.circleci/config.yml b/.circleci/config.yml index c47b7fd..95f4045 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,3 +66,21 @@ jobs: - run: name: lint example/keycloak-cloudfront-portal cloudfront command: cd example/keycloak-cloudfront-portal && npm run lint + - run: + name: lint example/chain-service-calls/frontend + command: cd example/chain-service-calls/frontend && npm run lint && npm i + - run: + name: lint example/chain-service-calls/service1 + command: cd example/chain-service-calls/service1 && npm run lint && npm i + - run: + name: lint example/chain-service-calls/service2 + command: cd example/chain-service-calls/service2 && npm run lint && npm i + - run: + name: lint example/chain-service-calls/service3 + command: cd example/chain-service-calls/service3 && npm run lint && npm i + - run: + name: lint example/express/frontend + command: cd example/express/frontend && npm run lint && npm i + - run: + name: lint example/express/express-service + command: cd example/express/express-service && npm run lint && npm i diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index bc9886d..bdc8bad 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -41,5 +41,9 @@ jobs: - run: cd example/keycloak-cloudfront-portal/lambda-edge-example && npm i && npm run build - run: cd example/keycloak-cloudfront-portal && npm i && npm run build - run: cd example/keycloak-cloudfront-portal && npm run lint + - run: cd example/chain-service-calls/frontend && npm run lint && npm i + - run: cd example/chain-service-calls/service1 && npm run lint && npm i + - run: cd example/chain-service-calls/service2 && npm run lint && npm i + - run: cd example/chain-service-calls/service3 && npm run lint && npm i diff --git a/README.md b/README.md index f2fae55..544713c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ npm install keycloak-lambda-authorizer -S ``` # Examples - [Serverless example (Api gateway with lambda authorizer)](example/keycloak-authorizer/README.md) + - [Example of expressjs middleware](example/express) - [Example of calling a chain of micro services, where each service is protected by its secured client](example/chain-service-calls) - [CloudFront with Lambda:Edge example](example/keycloak-cloudfront/README.md) - [CloudFront with portal authorization (switching between security realms)](example/keycloak-cloudfront-portal) @@ -729,6 +730,35 @@ keycloakJson, }); } ``` +## 15. ExpressJS middleware + +``` +const fs = require('fs'); +const { middlewareAdapter } = require('keycloak-lambda-authorizer'); + +function getKeycloakJSON() { + return JSON.parse(fs.readFileSync(`${__dirname}/keycloak.json`, 'utf8')); +} + +const app = express(); + +app.get('/expressServiceApi', middlewareAdapter( + getKeycloakJSON(), + { + enforce: { + enabled: true, + resource: { + name: 'service-api', + }, + }, + }, +).middleware, +async (request, response) => { + response.json({ + message: `Hi ${request.jwt.payload.preferred_username}. Your function executed successfully!`, + }); +}); +``` # If you find these useful, please [Donate](https://secure.wayforpay.com/button/b18610f33a01c)! diff --git a/example/chain-service-calls/README.md b/example/chain-service-calls/README.md index bd7c583..d7fc7de 100644 --- a/example/chain-service-calls/README.md +++ b/example/chain-service-calls/README.md @@ -14,10 +14,6 @@ sh bin/standalone.sh -c standalone.xml -b 0.0.0.0 -Djboss.bind.address.manageme ``` Open the Keycloak admin console, click on Add Realm, click on import 'Select file', select example-realm-export.json and click Create. -## 2. Run Serverless offline (Client Id and Secret credential Type) - -``` - ## 2. Run Services Locally - Service1 ```bash @@ -59,12 +55,6 @@ users: ## 6. Results -| User | Password | Service 1 Role 1 | Service 1 Role 2 | Service 2 Role | Service 3 Role | -|:----------|:-----------|:-----------------|:-----------------|:---------------|:---------------| -| user | user | X | X | X | X | -| user1 | user1 | - | - | X | X | -| user2 | user2 | X | - | - | X | - | User | Result | Description | |:----------|:-------------------------------------------------------------------------------------------------------|:------------------------------------------------------| | User | ![](../../docs/userChain.png) | All Access | diff --git a/example/express/README.md b/example/express/README.md new file mode 100644 index 0000000..caa20ba --- /dev/null +++ b/example/express/README.md @@ -0,0 +1,48 @@ +# Example expressjs middleware +![](../../keycloak-cross-client-authentication3.png) + +## 1. Start Keycloak + +### Docker +Using the image from https://hub.docker.com/r/jboss/keycloak/ +``` +docker run -p 8090:8080 -e JAVA_OPTS="-Dkeycloak.profile.feature.scripts=enabled -Dkeycloak.profile.feature.upload_scripts=enabled -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true" -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -v `pwd`/example/express:/express -e KEYCLOAK_IMPORT=/express/example-realm-export.json jboss/keycloak +``` +### Standard +``` +sh bin/standalone.sh -c standalone.xml -b 0.0.0.0 -Djboss.bind.address.management=0.0.0.0 --debug 8190 -Djboss.http.port=8090 +``` +Open the Keycloak admin console, click on Add Realm, click on import 'Select file', select example-realm-export.json and click Create. + +## 2. Run Services Locally +- Express Service +```bash +cd express-service +npm i +npm run start +``` + +## 3. Run UI locally + +```bash +cd frontend +npm i +npm run start +``` + +## 4. Open UI +[http://localhost:3001](http://localhost:3001) + +users: + +| User | Password | Service Role | +|:----------|:-----------|:-----------------| +| user | user | X | +| user1 | user1 | - | + +## 6. Results + +| User | Result | Description | +|:----------|:-------------------------------------------------------------------------------------------------------|:------------------------------------------------------| +| User | Hi user. Your function executed successfully! | All Access | +| User1 | Request failed with status code 403 | User has not access to express-service | diff --git a/example/express/example-realm-export.json b/example/express/example-realm-export.json new file mode 100644 index 0000000..803600e --- /dev/null +++ b/example/express/example-realm-export.json @@ -0,0 +1,2282 @@ +{ + "id": "express-example", + "realm": "express-example", + "notBefore": 0, + "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, + "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": "f00dea0b-1548-44b8-a339-32b92123875c", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "express-example", + "attributes": {} + }, + { + "id": "25c70409-4233-4333-8b37-a2d721e8d5e3", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "express-example", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "c109492e-ae5e-4b40-bc18-a17af35f20d8", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "fc316f58-89ba-4905-8f3a-cb8661ec9fa8", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "738d1878-e52c-4af5-abb5-3d62bf8aeeee", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-identity-providers", + "view-users", + "view-events", + "query-clients", + "view-authorization", + "query-realms", + "manage-users", + "view-realm", + "query-users", + "view-identity-providers", + "query-groups", + "manage-authorization", + "impersonation", + "view-clients", + "create-client", + "manage-realm", + "manage-clients", + "manage-events" + ] + } + }, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "23f1a052-fb7d-4bde-a55e-57c3cf55e50e", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "d5c95072-cb8f-4670-bbeb-bb680aad1595", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "8b7b2320-aa6c-40dc-8758-56ea21c2c976", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "adf910e1-01c8-424d-a756-f6fb47087192", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "8263fe10-712e-4d0a-a38f-cc1140cd8748", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "8498a2bd-2176-4b97-8497-127d82d654af", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "41c0cd12-bab6-4374-85b7-177bd7596442", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "2b6afd2c-0f61-435a-ada7-202667dc3e4f", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "f6a1dd28-0f76-41b4-9984-b9b32df5ecec", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "a8243854-573c-4691-ac39-2952fd01927e", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "15a296ee-d0fa-4b21-9231-7c76fa888428", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "1f468b04-9ce9-4907-9e24-5ae4422adda3", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "2ce75100-8ae7-4bc9-9aa7-2756239accfc", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "09b37684-0cf5-410f-be48-db8a4562c126", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "788ee0e2-aad7-47b9-8dfa-85fe64a215c2", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + }, + { + "id": "d6551f15-b895-4d9f-9f06-b31b826f4d89", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "attributes": {} + } + ], + "express-frontend": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "68df0a7f-c319-48fc-a3ef-a1d6ac23ea7c", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "06a1c95f-1cf4-4316-9684-9be8cda79193", + "attributes": {} + } + ], + "express-service": [ + { + "id": "9ba1969d-c3d2-410b-a13c-ebf7fb7cab7e", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "9e76cd8d-96ab-4472-9fff-f1582332c3f9", + "attributes": {} + }, + { + "id": "f3c2efc9-c523-40d4-994c-6ac1197c9261", + "name": "Service Role", + "composite": false, + "clientRole": true, + "containerId": "9e76cd8d-96ab-4472-9fff-f1582332c3f9", + "attributes": {} + } + ], + "account": [ + { + "id": "21ea40bb-f25d-4f25-831c-691fb9e14107", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "57432ca6-74f5-4c04-bf6d-3d9c2e7ec218", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "7a8dad09-cbd7-417b-92ca-9765d94a7a50", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "d2a291a6-be6d-47b2-a321-42ca6c0400f6", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "1554dc33-e010-41e9-bb24-45b6acb478b5", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "2b87189d-cb5f-4869-955e-6448e874f9a1", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + }, + { + "id": "bfabcc44-5e4c-46ff-b627-2b83abd86c88", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRoles": [ + "uma_authorization", + "offline_access" + ], + "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": [], + "users": [ + { + "username": "user1", + "enabled": true, + "email": "example-user1@example", + "firstName": "Lambda", + "lastName": "User1", + "credentials": [ + { + "type": "password", + "value": "user1" + } + ] + }, + { + "username": "user", + "enabled": true, + "email": "example-user@example", + "firstName": "Lambda", + "lastName": "User", + "credentials": [ + { + "type": "password", + "value": "user" + } + ], + "clientRoles": { + "express-service": [ + "Service Role" + ] + } + }, + { + "id": "2a5c3e52-4f3a-4a3b-87d4-1263e8b35fe8", + "createdTimestamp": 1619778578670, + "username": "service-account-express-service", + "enabled": true, + "totp": false, + "emailVerified": false, + "serviceAccountClientId": "express-service", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "uma_authorization", + "offline_access" + ], + "clientRoles": { + "express-service": [ + "uma_protection" + ], + "account": [ + "manage-account", + "view-profile" + ] + }, + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "1b31e265-5901-4dc2-9e75-e06e470f8878", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/express-example/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "defaultRoles": [ + "manage-account", + "view-profile" + ], + "redirectUris": [ + "/realms/express-example/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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "8eb8b46e-7e99-4b4f-8f02-32f35e48e548", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/express-example/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/realms/express-example/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": "89c0177e-5480-4755-808a-1bad71a4a811", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "f2083fe4-e391-421a-a146-26b11d5c1f89", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "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": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "06a1c95f-1cf4-4316-9684-9be8cda79193", + "clientId": "broker", + "name": "${client_broker}", + "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": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "efc92441-742a-4091-9e13-cba12b288f0a", + "clientId": "express-frontend", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "secret-frontend", + "redirectUris": [ + "*" + ], + "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", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "9e76cd8d-96ab-4472-9fff-f1582332c3f9", + "clientId": "express-service", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "secret-service", + "redirectUris": [ + "*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "saml.encrypt": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "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, + "protocolMappers": [ + { + "id": "efa3f4ac-1428-46bd-8a49-c1aa1bef00b6", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "3eea22e7-8abc-4699-ba68-0051d79dd2f7", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "63fb8617-0e31-449f-b63f-2a278f9290b7", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientId", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientId", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "service-api", + "ownerManagedAccess": false, + "attributes": {}, + "_id": "c127d685-6b86-4440-8659-a439994b2942", + "uris": [] + } + ], + "policies": [ + { + "id": "2812d781-58af-4e35-915d-f949514ed7a4", + "name": "service-api", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"express-service/Service Role\",\"required\":false}]" + } + }, + { + "id": "196d3a1c-bce9-495e-b916-06ac3f53f493", + "name": "service-api-permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"service-api\"]", + "applyPolicies": "[\"service-api\"]" + } + } + ], + "scopes": [], + "decisionStrategy": "UNANIMOUS" + } + }, + { + "id": "11ee3e4f-561c-4091-9411-2b1985a5f317", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "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": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "49a98bc7-a4dc-45e7-b1ec-547cf967b3dd", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/express-example/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/admin/express-example/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": "245ec3ea-e715-483a-85fe-133847ab3ac1", + "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "c9a164cb-b456-4311-adee-1eb54eb75d5e", + "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": "3df119d9-5ea8-452c-b540-10389fcdf46d", + "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": "0b636206-fcda-4700-a19d-72a0fd2d8b07", + "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": "bade32bd-1ed3-4e48-b64f-93f173c881a4", + "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": "09ac3e49-b8fe-4314-b690-0dbd6d21ec6c", + "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": "7d1c896d-05d5-4c6f-b08a-6e5fd8b1b496", + "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": "9c3576ec-a67c-4108-b530-d9346782900e", + "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": "c94e2fb2-54c8-4252-b5d3-71c457300efc", + "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": "80aa61e2-aefe-4066-b4f7-d72eeb2cc12f", + "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": "e781974b-0763-40c9-bf70-cfb21eedadf2", + "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": "85630036-ba44-44a0-9f1a-8e1f0407dc9b", + "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": "061c6fd1-a38b-41a3-9cf9-1aa7d54eaf28", + "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": "04a75dfa-0e4f-4fa1-9089-b285ac19d7d5", + "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": "216e906f-30bd-4800-8a81-7aeb012e35af", + "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": "75a99b87-4b79-4e98-ba1a-feb9f2efd2c1", + "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": "f5f714bb-c16f-49b8-91a5-18a47c7b22f0", + "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": "9e723de5-bd71-460c-9b3f-c8646b859b4a", + "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": "6e380eeb-ed07-4720-93da-680c3bcbe8ef", + "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": "0159e4ff-04ce-450c-a08f-e6d77d48be5e", + "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": "9d0cfe0c-004a-4b3f-af66-1a846a47c528", + "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": "408d4cf1-a674-403e-8c39-5f5eaf12ff55", + "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": "0fdd0abe-c093-4bc9-bee5-57aeb66d8ab8", + "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": "e2cc1e87-5e78-4ca9-9a04-25664a74a920", + "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": "49c51af4-1c0b-424e-a12c-16073ceb4ceb", + "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": "59d1774f-4165-4a87-9d21-9f33fb04d4e7", + "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": "37547eb3-b06e-43f5-8a41-07fd23e827b0", + "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": "0d6744c9-15ae-4a28-9685-6018aa241365", + "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": "40846f2d-35ed-47bf-ac13-ba05b4087150", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "7cdd64f3-0d2f-4dd4-8652-9ca0f9edc6cf", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "49d24529-e4e0-4dfd-b8ea-34dfcc7b4f19", + "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": "09c87636-a22d-4247-9063-7ab09ae1b4b6", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String" + } + }, + { + "id": "712a09f3-69e2-4b97-806f-e2cc07c05fef", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "92a4dcc0-466a-42ad-8208-6a3b57a55012", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "6edde41a-537c-4602-bc02-93efd6a97ef5", + "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": "8af420a1-cf99-46b5-a2ec-0deb840ed1ec", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + } + ], + "defaultDefaultClientScopes": [ + "profile", + "email", + "role_list", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "microprofile-jwt", + "offline_access", + "address", + "phone" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "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": "f4308d02-2f9a-4794-b781-e3e416fae4c7", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "209699c4-064c-4cd5-ba55-391341404bd4", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "b5031129-d3fa-486a-8c0d-c03a26657fa3", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "66b1bca1-a72c-4294-a732-44a8e8f23302", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "f76c961d-2a74-4b77-90b4-1297519fad2c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "0cf6727e-2a51-4b2f-b764-f5a1203c0e76", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "d4902aad-5e43-453f-bcdc-e0a30b56bf1b", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "17c098ed-bc52-4846-baee-4707bd0ecd3c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "saml-role-list-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "77af66c8-b61b-4484-bba0-fca639cfdc9a", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "a5f9fb36-dc78-442a-b3e9-edea1335e07e", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "13c886d1-51a2-4598-8156-e01affbe0802", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "0712c1e8-1e3d-4d90-84ac-b9f3eb74537f", + "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": "009f0bd0-b82a-4670-89f8-48370b121503", + "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": "59835a73-52f7-40f0-99fc-2a41ad52ce21", + "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": "9943ec9f-3660-4146-a9be-bf13131c8b15", + "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": "f9531ffe-5ae4-4a55-8bea-8826a48ada89", + "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": "52eb39e7-894a-451e-9ce5-14d4e63e3bae", + "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": "a477e6f1-334f-4e2a-af50-4fa6042e1ab1", + "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": "2a170b4f-383a-495e-9d10-1454d656200f", + "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": "b656f5ca-f277-4fb8-83c0-3c8d7640eac0", + "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": "1e9a22dd-d7a4-4670-8e55-e62869e5549d", + "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": "ef8810ab-83ff-49f0-810a-297b66c4df3b", + "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": "10f96148-3b4f-4300-9288-554712eea6bc", + "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": "f23edf0d-c9d3-49d0-8516-b20fcc2b131f", + "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": "844ba3de-252b-455f-a264-473795f5dfb0", + "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": "d86d2489-f666-4cf9-a4ae-d4c2bf739433", + "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": "58363a4c-d6ca-4f4b-8a0e-317cddee55aa", + "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": "afa5480d-cc5a-4e0e-8b22-b23d33c5f6ae", + "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": "e9ba4359-95e5-4370-b59e-9a2c3d889574", + "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": "501da1db-a3db-493b-acf0-a46bcba6fac9", + "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": "ff76d606-0dc5-49e6-82a2-ff19ac9a0f62", + "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": "0f03d4b4-98d8-48e8-aa13-b84880092f7f", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "2b3d26ca-2506-47c3-a702-4cddd4cb4e92", + "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": "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": "12.0.4", + "userManagedAccessAllowed": false +} diff --git a/example/express/express-service/index.js b/example/express/express-service/index.js new file mode 100644 index 0000000..45a4dde --- /dev/null +++ b/example/express/express-service/index.js @@ -0,0 +1,36 @@ +const fs = require('fs'); +const express = require('express'); +const { middlewareAdapter } = require('keycloak-lambda-authorizer'); +const bodyParser = require('body-parser'); +const { fetchData, sendData } = require('./restCalls'); + +function getKeycloakJSON() { + return JSON.parse(fs.readFileSync(`${__dirname}/keycloak.json`, 'utf8')); +} + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.get('/expressServiceApi', middlewareAdapter( + getKeycloakJSON(), + { + enforce: { + enabled: true, + resource: { + name: 'service-api', + }, + }, + }, +).middleware, +async (request, response) => { + response.json({ + message: `Hi ${request.jwt.payload.preferred_username}. Your function executed successfully!`, + }); +}); + +const server = app.listen(3002, () => { + const host = 'localhost'; + const { port } = server.address(); + console.log('Example app listening at http://%s:%s', host, port); +}); diff --git a/example/express/express-service/keycloak.json b/example/express/express-service/keycloak.json new file mode 100644 index 0000000..3dd5fea --- /dev/null +++ b/example/express/express-service/keycloak.json @@ -0,0 +1,13 @@ +{ + "realm": "express-example", + "auth-server-url": "http://localhost:8090/auth/", + "ssl-required": "external", + "resource": "express-service", + "verify-token-audience": true, + "credentials": { + "secret": "secret-service" + }, + "use-resource-role-mappings": true, + "confidential-port": 0, + "policy-enforcer": {} +} diff --git a/example/express/express-service/package.json b/example/express/express-service/package.json new file mode 100644 index 0000000..8d7b0f9 --- /dev/null +++ b/example/express/express-service/package.json @@ -0,0 +1,26 @@ +{ + "name": "chain-service-calls-service1", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node index.js", + "lint": "eslint --quiet --ext .js index.js", + "lint:fix": "eslint --fix --quiet --ext .js index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "vzakharchenko", + "license": "Apache-2.0", + "devDependencies": { + "eslint": "*", + "eslint-config-airbnb": "*", + "eslint-plugin-import": "*" + }, + "dependencies": { + "axios": "*", + "body-parser": "*", + "express": "*", + "jsonwebtoken": "*", + "keycloak-lambda-authorizer": "../../../" + } +} diff --git a/example/express/express-service/restCalls.js b/example/express/express-service/restCalls.js new file mode 100644 index 0000000..1645e80 --- /dev/null +++ b/example/express/express-service/restCalls.js @@ -0,0 +1,49 @@ +const fetch = require('axios'); + +fetch.interceptors.response.use((response) => response, (error) => error); + +function fetchData(url, method = 'GET', headers) { + return new Promise((resolve, reject) => { + fetch({ + url, + method, + headers, + transformResponse: (req) => req, + withCredentials: true, + timeout: 29000, + }).then((response) => { + if (response.isAxiosError) { + reject(response.message); + } + resolve(response.data); + }).catch((response) => { + reject(response); + }); + }); +} + +function sendData(url, method = 'POST', data, headers) { + return new Promise((resolve, reject) => { + fetch({ + url, + method, + data, + headers, + transformResponse: (req) => req, + withCredentials: true, + timeout: 29000, + }).then((response) => { + if (response.isAxiosError) { + reject(response.message); + } + resolve(response.data); + }).catch((response) => { + reject(response); + }); + }); +} + +module.exports = { + fetchData, + sendData, +}; diff --git a/example/express/frontend/index.js b/example/express/frontend/index.js new file mode 100644 index 0000000..afacf1e --- /dev/null +++ b/example/express/frontend/index.js @@ -0,0 +1,78 @@ +const jsonwebtoken = require('jsonwebtoken'); +const express = require('express'); +const exphbs = require('express-handlebars'); +const Keycloak = require('keycloak-connect'); +const path = require('path'); +const bodyParser = require('body-parser'); +const session = require('express-session'); +const { fetchData, sendData } = require('./restCalls'); + +const app = express(); +const memoryStore = new session.MemoryStore(); +const state = { + status1: '', + status1Token: '', +}; + +app.use(session({ + secret: 'mySecret', + resave: false, + saveUninitialized: true, + store: memoryStore, +})); + +const keycloak = new Keycloak({ + store: memoryStore, +}); + +app.use(keycloak.middleware()); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.engine('.hbs', exphbs({ + defaultLayout: 'main', + extname: '.hbs', + layoutsDir: path.join(__dirname, 'views/layouts'), +})); + +app.set('view engine', '.hbs'); + +app.set('views', path.join(__dirname, 'views')); + +function renderUI(request, response, data) { + response.render('home', { + host1: process.env.SERVICE_URL, + ...data, + }); +} + +app.post('/express', keycloak.protect(), async (request, response) => { + const lambdaJWT = JSON.parse(request.session['keycloak-token']); + try { + const res = await fetchData(`${process.env.SERVICE_URL}expressServiceApi`, 'GET', { + Authorization: `Bearer ${lambdaJWT.access_token}`, + }); + renderUI(request, response, { + status1: JSON + .parse(res).message, + status1Token: JSON + .stringify(jsonwebtoken.decode(lambdaJWT.access_token), null, 2), + }); + } catch (e) { + renderUI(request, response, { + status1: e, + status1Token: JSON + .stringify(jsonwebtoken.decode(lambdaJWT.access_token), null, 2), + }); + } +}); + +app.get('/', keycloak.protect(), (request, response) => { + renderUI(request, response, '', ''); +}); + +const server = app.listen(3001, () => { + const host = 'localhost'; + const { port } = server.address(); + console.log('Example app listening at http://%s:%s', host, port); +}); diff --git a/example/express/frontend/keycloak.json b/example/express/frontend/keycloak.json new file mode 100644 index 0000000..7885c86 --- /dev/null +++ b/example/express/frontend/keycloak.json @@ -0,0 +1,10 @@ +{ + "realm": "express-example", + "auth-server-url": "http://localhost:8090/auth/", + "ssl-required": "external", + "resource": "express-frontend", + "credentials": { + "secret": "secret-frontend" + }, + "confidential-port": 0 +} diff --git a/example/express/frontend/package.json b/example/express/frontend/package.json new file mode 100644 index 0000000..8ce15b1 --- /dev/null +++ b/example/express/frontend/package.json @@ -0,0 +1,29 @@ +{ + "name": "chain-service-calls-frontend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "SERVICE_URL=http://localhost:3002/ node index.js", + "lint": "eslint --quiet --ext .js index.js", + "lint:fix": "eslint --fix --quiet --ext .js index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "vzakharchenko", + "license": "Apache-2.0", + "devDependencies": { + "eslint": "*", + "eslint-config-airbnb": "*", + "eslint-plugin-import": "*" + }, + "dependencies": { + "axios": "*", + "body-parser": "*", + "express": "*", + "express-handlebars": "*", + "express-session": "*", + "jsonwebtoken": "*", + "keycloak-connect": "*", + "path": "*" + } +} diff --git a/example/express/frontend/restCalls.js b/example/express/frontend/restCalls.js new file mode 100644 index 0000000..1645e80 --- /dev/null +++ b/example/express/frontend/restCalls.js @@ -0,0 +1,49 @@ +const fetch = require('axios'); + +fetch.interceptors.response.use((response) => response, (error) => error); + +function fetchData(url, method = 'GET', headers) { + return new Promise((resolve, reject) => { + fetch({ + url, + method, + headers, + transformResponse: (req) => req, + withCredentials: true, + timeout: 29000, + }).then((response) => { + if (response.isAxiosError) { + reject(response.message); + } + resolve(response.data); + }).catch((response) => { + reject(response); + }); + }); +} + +function sendData(url, method = 'POST', data, headers) { + return new Promise((resolve, reject) => { + fetch({ + url, + method, + data, + headers, + transformResponse: (req) => req, + withCredentials: true, + timeout: 29000, + }).then((response) => { + if (response.isAxiosError) { + reject(response.message); + } + resolve(response.data); + }).catch((response) => { + reject(response); + }); + }); +} + +module.exports = { + fetchData, + sendData, +}; diff --git a/example/express/frontend/views/home.hbs b/example/express/frontend/views/home.hbs new file mode 100644 index 0000000..0e2a6e8 --- /dev/null +++ b/example/express/frontend/views/home.hbs @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + +
Invoke Lambda
Express urlInvoke APIService ResponseAccess Token
{{host1}}{{status1}}{{status1Token}}
+ diff --git a/example/express/frontend/views/layouts/main.hbs b/example/express/frontend/views/layouts/main.hbs new file mode 100644 index 0000000..91c2c48 --- /dev/null +++ b/example/express/frontend/views/layouts/main.hbs @@ -0,0 +1,8 @@ + + + Express handlebars + + + {{{body}}} + + \ No newline at end of file