{"id":15779978,"url":"https://github.com/rgl/terraform-keycloak","last_synced_at":"2026-02-03T03:34:57.757Z","repository":{"id":63732114,"uuid":"570283824","full_name":"rgl/terraform-keycloak","owner":"rgl","description":"Keycloak playground","archived":false,"fork":false,"pushed_at":"2024-08-29T18:10:09.000Z","size":909,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-05T18:22:11.618Z","etag":null,"topics":["keycloak","oauth2","oauth2-client","oauth2-server","oidc","saml","saml-service-provider","saml2","terraform"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rgl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-24T19:37:24.000Z","updated_at":"2024-08-29T18:10:15.000Z","dependencies_parsed_at":"2023-12-25T08:33:17.913Z","dependency_job_id":"20cb111b-0f7b-41d0-abb7-6bbcaf0967ad","html_url":"https://github.com/rgl/terraform-keycloak","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fterraform-keycloak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fterraform-keycloak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fterraform-keycloak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fterraform-keycloak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rgl","download_url":"https://codeload.github.com/rgl/terraform-keycloak/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221450022,"owners_count":16823732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keycloak","oauth2","oauth2-client","oauth2-server","oidc","saml","saml-service-provider","saml2","terraform"],"created_at":"2024-10-04T18:22:11.184Z","updated_at":"2026-02-03T03:34:57.713Z","avatar_url":"https://github.com/rgl.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About\n\n[![Build status](https://github.com/rgl/terraform-keycloak/workflows/build/badge.svg)](https://github.com/rgl/terraform-keycloak/actions?query=workflow%3Abuild)\n\nThis initializes a Keycloak instance using the [mrparkers/terraform-provider-keycloak](https://github.com/mrparkers/terraform-provider-keycloak) Terraform provider.\n\nThis will:\n\n* Create an example private certification authority.\n  * Use it to sign all the used HTTPS certificates.\n* Create a test Keycloak instance inside a docker container using docker compose.\n* Create the `example` realm.\n  * Configure the User Profile.\n    * Add the `department` custom attribute.\n  * Create the `alice` user.\n    * Add the `department` custom attribute.\n  * Create the `administrators` group.\n    * Assign the `example-go-saml` client `administrator` role.\n    * Add the `alice` user as a member.\n  * Create the `example-bash-password-client` client.\n    * Add the `department` custom claim derived from the `department` user custom attribute.\n  * Create the `example-csharp-public-device` client.\n  * Create the `example-csharp-client-credentials-server` client.\n  * Create the `example-csharp-client-credentials-server-test` client.\n    * Add the `project` custom claim.\n  * Create the `example-go-client-credentials-server` client.\n  * Create the `example-go-client-credentials-server-test` client.\n    * Add the `project` custom claim.\n  * Create the `example-go-confidential` client.\n  * Create the `example-go-saml` client.\n    * Create the `administrator` role.\n  * Create the `example-react-public` client.\n* Start the example `example-csharp-public-device` client (and test it).\n  * Uses the [OAuth 2.0 Device Authorization Grant](https://oauth.net/2/device-flow/) (aka Device Flow).\n* Start the example `example-csharp-client-credentials-server` server.\n  * Authorizes client requests using [OAuth Access Tokens](https://oauth.net/2/access-tokens/) (specifically, [OAuth 2.0 Bearer Tokens](https://oauth.net/2/bearer-tokens/)).\n* Start the example `example-go-client-credentials-server` server.\n  * Authorizes client requests using [OAuth Access Tokens](https://oauth.net/2/access-tokens/) (specifically, [OAuth 2.0 Bearer Tokens](https://oauth.net/2/bearer-tokens/)).\n* Start the example `example-go-client-credentials-server-test` client.\n  * Uses the [OAuth 2.0 Client Credentials Grant](https://oauth.net/2/grant-types/client-credentials/).\n* Start the example `example-go-confidential` client (and test it).\n  * Uses the [OAuth 2.0 Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code/).\n  * Uses the [Proof Key for Code Exchange (PKCE)](https://oauth.net/2/pkce/) extension.\n* Start the example `example-go-saml` client (and test it).\n  * Uses [SAML 2.0](https://en.wikipedia.org/wiki/SAML_2.0).\n* Start the example `example-react-public` client (and test it).\n  * Uses [OAuth 2.0 Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code/).\n  * Uses the [Proof Key for Code Exchange (PKCE)](https://oauth.net/2/pkce/) extension.\n\n# Usage\n\nInstall docker compose.\n\nAdd the following to your machine `hosts` file:\n\n```\n127.0.0.1 keycloak.test\n127.0.0.1 mail.test\n127.0.0.1 example-csharp-client-credentials-server.test\n127.0.0.1 example-go-client-credentials-server.test\n127.0.0.1 example-go-confidential.test\n127.0.0.1 example-go-saml.test\n127.0.0.1 example-react-public.test\n```\n\nStart the environment:\n\n```bash\n./create.sh\n```\n\nConfigure your Firefox Snap to trust the Keycloak CA:\n\n```bash\nnssdb_path=\"$(dirname ~/snap/firefox/common/.mozilla/firefox/*/cert9.db)\"\n# list the trusted cas.\ncertutil -L -d \"sql:$nssdb_path\"\n# delete the ca.\n# NB this errors when it does not exist.\ncertutil -D -d \"sql:$nssdb_path\" -n terraform-keycloak\n# trust the ca.\ncertutil -A -d \"sql:$nssdb_path\" -n terraform-keycloak \\\n  -i tmp/keycloak-ca/keycloak-ca-crt.pem \\\n  -t 'C,,'\n```\n\nTry the example applications displayed by the above command. E.g., try the\nOpenID Connect Confidential Client as the `alice`:`alice` user at:\n\nhttps://example-go-confidential.test:8081/auth/login\n\nWhen anything goes wrong, you can try to troubleshoot at:\n\n* `docker compose logs --follow`\n* https://keycloak.test:8443/realms/example/.well-known/openid-configuration (Keycloak OIDC configuration)\n* https://keycloak.test:8443/realms/example/protocol/saml/descriptor (Keycloak SAML configuration)\n* https://keycloak.test:8443 (Keycloak; login as `admin`:`admin`)\n* https://mail.test:8025 (Mailpit (email server))\n* For SAML troubleshooting, you can use the browser developer tools to capture\n  the requests/responses and paste them in the SAML Decoder \u0026 Parser at\n  https://www.scottbrady91.com/tools/saml-parser.\n\nManually try the Go OAuth 2.0 Client Credentials Grant from bash:\n\n```bash\n# NB this is the bash equivalent of:\n#     clients/example-go-client-credentials-server-test\n#     clients/example-go-client-credentials-server\nexport SSL_CERT_FILE=\"$PWD/tmp/keycloak-ca/keycloak-ca-crt.pem\"\ntoken_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token'\nintrospection_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token/introspect'\nclient_id='example-go-client-credentials-server-test'\nclient_secret='example'\nserver_client_id='example-go-client-credentials-server'\nserver_client_secret='example'\ntoken_response=\"$(curl \\\n  -s \\\n  -X POST \\\n  -u \"$client_id:$client_secret\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=$client_id\" \\\n  -d \"client_secret=$client_secret\" \\\n  \"$token_url\")\"\njq \u003c\u003c\u003c\"$token_response\"\n# NB In Keycloak, this token is a JWT (as defined in the JSON Web Token (JWT)\n#    Profile for OAuth 2.0 Access Tokens at\n#    https://datatracker.ietf.org/doc/html/rfc9068).\n# NB This means we can also use the Keycloak OIDC configuration endpoint at\n#    https://keycloak.test:8443/realms/example/.well-known/openid-configuration\n#    to drive the token validation based in the JWT issuer URL, like we do in:\n#     clients/example-go-confidential\n#     clients/example-react-public\ntoken=\"$(jq -r .access_token \u003c\u003c\u003c\"$token_response\")\"\n# show the (access) token claims.\nperl -ne '/.+\\.(.+)\\.(.+)/ \u0026\u0026 print $1' \u003c\u003c\u003c\"$token\" | base64 -d 2\u003e/dev/null | jq\n# show the claims returned by the introspection url.\ncurl \\\n  -s \\\n  -X POST \\\n  -u \"$server_client_id:$server_client_secret\" \\\n  -d \"token=$token\" \\\n  \"$introspection_url\" \\\n  | jq\n```\n\nThis should return the following claims and values, something alike:\n\n**NB** Notice the presence of the `project` custom claim.\n\n```json\n{\n  \"exp\": 1713382890,\n  \"iat\": 1713382590,\n  \"jti\": \"fdbae048-85ab-4449-a77e-06d03ac885a1\",\n  \"iss\": \"https://keycloak.test:8443/realms/example\",\n  \"aud\": \"account\",\n  \"sub\": \"3b00d462-9106-420e-97e9-542c4874d36f\",\n  \"typ\": \"Bearer\",\n  \"azp\": \"example-go-client-credentials-server-test\",\n  \"acr\": \"1\",\n  \"realm_access\": {\n    \"roles\": [\n      \"offline_access\",\n      \"default-roles-example\",\n      \"uma_authorization\"\n    ]\n  },\n  \"resource_access\": {\n    \"account\": {\n      \"roles\": [\n        \"manage-account\",\n        \"manage-account-links\",\n        \"view-profile\"\n      ]\n    }\n  },\n  \"scope\": \"email profile\",\n  \"email_verified\": false,\n  \"project\": \"example\",\n  \"preferred_username\": \"service-account-example-go-client-credentials-server-test\",\n  \"client_id\": \"example-go-client-credentials-server-test\",\n  \"username\": \"service-account-example-go-client-credentials-server-test\",\n  \"token_type\": \"Bearer\",\n  \"active\": true\n}\n```\n\nManually try the C# OAuth 2.0 Client Credentials Grant from bash:\n\n```bash\n# NB this is the bash equivalent of:\n#     clients/example-csharp-client-credentials-server-test\n#     clients/example-csharp-client-credentials-server\nexport SSL_CERT_FILE=\"$PWD/tmp/keycloak-ca/keycloak-ca-crt.pem\"\ntoken_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token'\nintrospection_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token/introspect'\nclient_id='example-csharp-client-credentials-server-test'\nclient_secret='example'\nserver_url='https://example-csharp-client-credentials-server.test:8027'\nserver_client_id='example-csharp-client-credentials-server'\nserver_client_secret='example'\ntoken_response=\"$(curl \\\n  -s \\\n  -X POST \\\n  -u \"$client_id:$client_secret\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=$client_id\" \\\n  -d \"client_secret=$client_secret\" \\\n  \"$token_url\")\"\njq \u003c\u003c\u003c\"$token_response\"\n# NB In Keycloak, this token is a JWT (as defined in the JSON Web Token (JWT)\n#    Profile for OAuth 2.0 Access Tokens at\n#    https://datatracker.ietf.org/doc/html/rfc9068).\n# NB This means we can also use the Keycloak OIDC configuration endpoint at\n#    https://keycloak.test:8443/realms/example/.well-known/openid-configuration\n#    to drive the token validation based in the JWT issuer URL, like we do in:\n#     clients/example-csharp-client-credentials-server\n#     clients/example-go-confidential\n#     clients/example-react-public\ntoken=\"$(jq -r .access_token \u003c\u003c\u003c\"$token_response\")\"\n# show the (access) token claims.\nperl -ne '/.+\\.(.+)\\.(.+)/ \u0026\u0026 print $1' \u003c\u003c\u003c\"$token\" | base64 -d 2\u003e/dev/null | jq\n# show the claims returned by the introspection url.\ncurl \\\n  -s \\\n  -X POST \\\n  -u \"$server_client_id:$server_client_secret\" \\\n  -d \"token=$token\" \\\n  \"$introspection_url\" \\\n  | jq\n```\n\nThis should return the following claims and values, something alike:\n\n**NB** Notice the presence of the `project` custom claim.\n\n```json\n{\n  \"exp\": 1713382969,\n  \"iat\": 1713382669,\n  \"jti\": \"4a443912-8e19-471f-b301-1e5c98d904de\",\n  \"iss\": \"https://keycloak.test:8443/realms/example\",\n  \"aud\": \"account\",\n  \"sub\": \"7da88c59-397e-4ec8-959f-0125b1ad73e3\",\n  \"typ\": \"Bearer\",\n  \"azp\": \"example-csharp-client-credentials-server-test\",\n  \"acr\": \"1\",\n  \"realm_access\": {\n    \"roles\": [\n      \"offline_access\",\n      \"default-roles-example\",\n      \"uma_authorization\"\n    ]\n  },\n  \"resource_access\": {\n    \"account\": {\n      \"roles\": [\n        \"manage-account\",\n        \"manage-account-links\",\n        \"view-profile\"\n      ]\n    }\n  },\n  \"scope\": \"email profile\",\n  \"email_verified\": false,\n  \"project\": \"example\",\n  \"preferred_username\": \"service-account-example-csharp-client-credentials-server-test\",\n  \"client_id\": \"example-csharp-client-credentials-server-test\",\n  \"username\": \"service-account-example-csharp-client-credentials-server-test\",\n  \"token_type\": \"Bearer\",\n  \"active\": true\n}\n```\n\nTry calling the `example-csharp-client-credentials-server` service using the access token:\n\n```bash\n# NB when there is an error, the www-authenticate response header contains\n#    the error. for example:\n#       www-authenticate: Bearer error=\"invalid_token\", error_description=\"The token expired at '04/14/2024 10:43:45'\"\ncurl \\\n  -s \\\n  -X GET \\\n  -H \"Authorization: Bearer $token\" \\\n  \"$server_url/protected\" \\\n  | jq\n```\n\nThis should return the following claims and values, something alike:\n\n**NB** Notice the presence of the `project` custom claim.\n\n```json\n{\n  \"Claims\": [\n    {\n      \"Name\": \"exp\",\n      \"Value\": \"1713382969\"\n    },\n    {\n      \"Name\": \"iat\",\n      \"Value\": \"1713382669\"\n    },\n    {\n      \"Name\": \"jti\",\n      \"Value\": \"4a443912-8e19-471f-b301-1e5c98d904de\"\n    },\n    {\n      \"Name\": \"iss\",\n      \"Value\": \"https://keycloak.test:8443/realms/example\"\n    },\n    {\n      \"Name\": \"aud\",\n      \"Value\": \"account\"\n    },\n    {\n      \"Name\": \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\",\n      \"Value\": \"7da88c59-397e-4ec8-959f-0125b1ad73e3\"\n    },\n    {\n      \"Name\": \"typ\",\n      \"Value\": \"Bearer\"\n    },\n    {\n      \"Name\": \"azp\",\n      \"Value\": \"example-csharp-client-credentials-server-test\"\n    },\n    {\n      \"Name\": \"http://schemas.microsoft.com/claims/authnclassreference\",\n      \"Value\": \"1\"\n    },\n    {\n      \"Name\": \"realm_access\",\n      \"Value\": \"{\\\"roles\\\":[\\\"offline_access\\\",\\\"default-roles-example\\\",\\\"uma_authorization\\\"]}\"\n    },\n    {\n      \"Name\": \"resource_access\",\n      \"Value\": \"{\\\"account\\\":{\\\"roles\\\":[\\\"manage-account\\\",\\\"manage-account-links\\\",\\\"view-profile\\\"]}}\"\n    },\n    {\n      \"Name\": \"scope\",\n      \"Value\": \"email profile\"\n    },\n    {\n      \"Name\": \"clientHost\",\n      \"Value\": \"172.19.0.1\"\n    },\n    {\n      \"Name\": \"email_verified\",\n      \"Value\": \"false\"\n    },\n    {\n      \"Name\": \"project\",\n      \"Value\": \"example\"\n    },\n    {\n      \"Name\": \"preferred_username\",\n      \"Value\": \"service-account-example-csharp-client-credentials-server-test\"\n    },\n    {\n      \"Name\": \"clientAddress\",\n      \"Value\": \"172.19.0.1\"\n    },\n    {\n      \"Name\": \"client_id\",\n      \"Value\": \"example-csharp-client-credentials-server-test\"\n    }\n  ]\n}\n```\n\nTry OAuth 2.0 Resource Owner Password Credentials Grant (aka Direct Access Grant; aka Password Grant) from bash:\n\n**NB** Although this OAuth 2.0 Grant is supported by Keycloak, its not a [OAuth 2.0 Security Best Current Practice](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-resource-owner-password-cre).\n\n```bash\nexport SSL_CERT_FILE=\"$PWD/tmp/keycloak-ca/keycloak-ca-crt.pem\"\ntoken_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token'\nintrospection_url='https://keycloak.test:8443/realms/example/protocol/openid-connect/token/introspect'\nclient_id='example-bash-password-client'\nclient_secret='example'\nuser_username='alice'\nuser_password='alice'\nserver_url='https://example-csharp-client-credentials-server.test:8027'\nserver_client_id='example-csharp-client-credentials-server'\nserver_client_secret='example'\ntoken_response=\"$(curl \\\n  -s \\\n  -X POST \\\n  -u \"$client_id:$client_secret\" \\\n  -d \"grant_type=password\" \\\n  -d \"client_id=$client_id\" \\\n  -d \"client_secret=$client_secret\" \\\n  -d \"username=$user_username\" \\\n  -d \"password=$user_password\" \\\n  \"$token_url\")\"\njq \u003c\u003c\u003c\"$token_response\"\n# NB In Keycloak, this token is a JWT (as defined in the JSON Web Token (JWT)\n#    Profile for OAuth 2.0 Access Tokens at\n#    https://datatracker.ietf.org/doc/html/rfc9068).\n# NB This means we can also use the Keycloak OIDC configuration endpoint at\n#    https://keycloak.test:8443/realms/example/.well-known/openid-configuration\n#    to drive the token validation based in the JWT issuer URL, like we do in:\n#     clients/example-csharp-client-credentials-server\n#     clients/example-go-confidential\n#     clients/example-react-public\ntoken=\"$(jq -r .access_token \u003c\u003c\u003c\"$token_response\")\"\n# show the (access) token claims.\nperl -ne '/.+\\.(.+)\\.(.+)/ \u0026\u0026 print $1' \u003c\u003c\u003c\"$token\" | base64 -d 2\u003e/dev/null | jq\n# show the claims returned by the introspection url.\ncurl \\\n  -s \\\n  -X POST \\\n  -u \"$server_client_id:$server_client_secret\" \\\n  -d \"token=$token\" \\\n  \"$introspection_url\" \\\n  | jq\n```\n\nThis should return the following claims and values, something alike:\n\n**NB** Notice the presence of the `department` custom claim.\n\n```json\n{\n  \"exp\": 1713632625,\n  \"iat\": 1713632325,\n  \"jti\": \"cb9af167-43b9-4884-a0b9-b0ea856e8e03\",\n  \"iss\": \"https://keycloak.test:8443/realms/example\",\n  \"aud\": [\n    \"example-go-saml\",\n    \"account\"\n  ],\n  \"sub\": \"dc4bde45-1211-45c2-bbfd-fcba56d40e12\",\n  \"typ\": \"Bearer\",\n  \"azp\": \"example-bash-password-client\",\n  \"session_state\": \"fbdd975c-aa21-4fca-9884-8a85964bf101\",\n  \"acr\": \"1\",\n  \"realm_access\": {\n    \"roles\": [\n      \"offline_access\",\n      \"default-roles-example\",\n      \"uma_authorization\"\n    ]\n  },\n  \"resource_access\": {\n    \"example-go-saml\": {\n      \"roles\": [\n        \"administrator\"\n      ]\n    },\n    \"account\": {\n      \"roles\": [\n        \"manage-account\",\n        \"manage-account-links\",\n        \"view-profile\"\n      ]\n    }\n  },\n  \"scope\": \"profile email\",\n  \"sid\": \"fbdd975c-aa21-4fca-9884-8a85964bf101\",\n  \"email_verified\": true,\n  \"name\": \"Alice Doe\",\n  \"preferred_username\": \"alice\",\n  \"department\": \"example\",\n  \"given_name\": \"Alice\",\n  \"family_name\": \"Doe\",\n  \"email\": \"alice@example.com\",\n  \"client_id\": \"example-bash-password-client\",\n  \"username\": \"alice\",\n  \"token_type\": \"Bearer\",\n  \"active\": true\n}\n```\n\nDestroy everything:\n\n```bash\n./destroy.sh\n```\n\nList this repository dependencies (and which have newer versions):\n\n```bash\nexport GITHUB_COM_TOKEN='YOUR_GITHUB_PERSONAL_TOKEN'\n./renovate.sh\n```\n\n# Alternatives\n\n* [Authelia](https://www.authelia.com)\n* [Dex](https://dexidp.io)\n* [OAuth2 Proxy](https://github.com/oauth2-proxy/oauth2-proxy)\n* [Ory Hydra](https://www.ory.sh)\n* [Zitadel](https://github.com/zitadel/zitadel)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frgl%2Fterraform-keycloak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frgl%2Fterraform-keycloak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frgl%2Fterraform-keycloak/lists"}