Keycloak
When you finish this page, your workspace's people sign in with their Keycloak accounts, through a client in your realm. The client speaks either OpenID Connect or SAML. These steps were checked on Keycloak 26.4, with OpenID Connect and with SAML (signed requests).
Before you start
Section titled “Before you start”- Sign-in is on for your runtime, and you're an admin of the workspace,
with the
kindgiCLI set up as Set up SSO says. - Admin access to your Keycloak realm, on Keycloak 26.4 or a release whose admin console has the same fields.
- For SAML,
openssl, to make Kindgi's signing key and certificate. - For
kindgicommands: Kindgi 0.1's CLI, which runs from any folder asnpx --yes @kindgi/cli@0.1(Install). Inside a pack project,pnpm exec kindgiruns the project's pinned CLI instead.
OpenID Connect
Section titled “OpenID Connect”1. Get the redirect URI
Section titled “1. Get the redirect URI”start gives you the redirect URI to enter in Keycloak:
npx --yes @kindgi/cli@0.1 sso providers start acme-kc --idp=keycloakacme-kcis the provider's id in your workspace.--idp=keycloakadds Keycloak's own steps to the message.
Sign-in with "acme-kc" (OpenID Connect). Send this to whoever runs your identity provider:
Create an OpenID Connect web application (a confidential client) for Kindgi. Redirect URI: http://localhost:18096/auth/sso/callback/idp-ibhu3tdkkrjjjfllbjpu2uk3gm Scopes: openid email profile Let in only the people who should use Kindgi (assign users or groups).
Send back: the issuer URL and the client ID. The client secret goes into Kindgi's secret store under a name, never by email or chat: kindgi secrets set <NAME> --env=<runtime env> --scope=tenant
Keycloak admin console → your realm → Clients → Create client → OpenID Connect: 1. Client authentication: On. Authentication flow: Standard flow. 2. Valid redirect URIs: the URI above (exactly; no wildcard). 3. Credentials tab: copy the client secret. 4. Each person needs an email with "Email verified" on, or sign-in is refused.Issuer: https://<keycloak-host>/realms/<realm>
Step by step: https://docs.kindgi.com/v0.1/guides/sso/keycloak/
Then register it: kindgi sso providers finish acme-kc --kind=oidc --issuer=<issuer> --client-id=<client-id> --client-secret-ref=<NAME> --domains=<your-domain>
These URLs stay the same after registering and after any `update`.2. Create the client in Keycloak
Section titled “2. Create the client in Keycloak”In the Keycloak admin console, in your realm, open Clients → Create client, and choose the client type OpenID Connect:
- On the second step: turn Client authentication On, for a confidential client. Choose the Authentication flow Standard flow, and the PKCE Method S256.
- On the third step, Valid redirect URIs: enter the redirect URI that
startprinted, exactly, with no wildcard. - On the client's Credentials tab: copy the Client secret.
- For each person: turn Email verified On, under Users → the person → Details. Without it, Kindgi refuses their sign-in: "Your email isn't verified".
3. Store the client secret
Section titled “3. Store the client secret”Store the secret in Kindgi's secret store, by name, so it never travels by email or chat:
npx --yes @kindgi/cli@0.1 secrets set ACME_KC_SECRET --env=production --scope=tenantACME_KC_SECRETis the secret's name. The registration keeps only this name.--envis the runtime's environment, itsKINDGI_ENV.--scope=tenantstores the secret for the whole workspace.
The command asks for the value twice, and doesn't show what you type. Then it prints what it stored:
Value:Re-enter to confirm:{ "name": "ACME_KC_SECRET", "scope": { "kind": "tenant", "tenantId": "6c0bd33e-e941-439b-bd0c-c7e412db29fc" }, "envName": "production", "versionId": 1}
Set ACME_KC_SECRET at tenant in production.4. Register it
Section titled “4. Register it”finish registers the client, and offers it to people at your domains:
npx --yes @kindgi/cli@0.1 sso providers finish acme-kc --kind=oidc --issuer=https://<keycloak-host>/realms/<realm> \ --client-id=<client id> --client-secret-ref=ACME_KC_SECRET --domains=<your domain>--issueris your realm's URL.<keycloak-host>is your Keycloak's address, and<realm>the realm's name.<client id>is the client's Client ID from step 2.--client-secret-refis the secret's name from step 3.<your domain>is your organization's email domain, such asacme.com. For more than one, separate them with commas.
finish prints the registration
(Set up SSO shows one).
Keycloak's SAML metadata always asks for signed sign-in requests. So a Keycloak SAML client needs a signing key and certificate for Kindgi.
1. Get the SAML URLs
Section titled “1. Get the SAML URLs”start with --kind=saml gives you the URLs a SAML client asks for:
npx --yes @kindgi/cli@0.1 sso providers start acme-saml --kind=samlacme-samlis the provider's id in your workspace.--kind=samlasks for a SAML provider's URLs: its ACS URL and its entity ID.
Sign-in with "acme-saml" (SAML). Send this to whoever runs your identity provider:
Create a SAML 2.0 application for Kindgi. ACS URL (single sign-on URL): http://localhost:18096/auth/sso/saml2/sp/acs/idp-o2ff6ocaeflrtl4qeknbutvlru Entity ID (audience): http://localhost:18096/auth/sso/saml2/sp/metadata?providerId=idp-o2ff6ocaeflrtl4qeknbutvlru Service provider metadata: http://localhost:18096/auth/sso/saml2/sp/metadata?providerId=idp-o2ff6ocaeflrtl4qeknbutvlru Name ID: the email address (or an `email` attribute). Sign the assertions. Let in only the people who should use Kindgi (assign users or groups).
Send back: the identity provider's metadata XML.
Step by step: https://docs.kindgi.com/v0.1/guides/sso/saml/
Then register it: kindgi sso providers finish acme-saml --kind=saml --idp-metadata=@<metadata.xml> --domains=<your-domain>
These URLs stay the same after registering and after any `update`.2. Make Kindgi's signing key and certificate
Section titled “2. Make Kindgi's signing key and certificate”Kindgi signs its sign-in requests with this key, and Keycloak checks them with the certificate. Make both, and store the key in Kindgi's secret store by name:
openssl req -x509 -newkey rsa:2048 -nodes -keyout acme-sp-key.pem -out acme-sp-cert.pem -days 730 -subj "/CN=Kindgi SAML (acme.test)"npx --yes @kindgi/cli@0.1 secrets set ACME_SAML_SIGNING_KEY --env=production --scope=tenant --from-stdin < acme-sp-key.pemreq -x509makes a self-signed certificate, and-newkey rsa:2048a new 2048-bit RSA key for it.-nodesleaves the key file unencrypted, so Kindgi can read it.-keyoutand-outname the key's file and the certificate's file.-days 730makes the certificate last two years.-subjsets the certificate's name. Use your own domain in it.--from-stdinmakessetread the key from its input, instead of asking for it.< acme-sp-key.pemgives it the key file as that input.
openssl prints its progress, then a line of dashes. Then set prints what
it stored:
…-----{ "name": "ACME_SAML_SIGNING_KEY", "scope": { "kind": "tenant", "tenantId": "6c0bd33e-e941-439b-bd0c-c7e412db29fc" }, "envName": "production", "versionId": 1}
Set ACME_SAML_SIGNING_KEY at tenant in production.Give the certificate, acme-sp-cert.pem, to whoever runs Keycloak. The key
stays in the secret store. Delete acme-sp-key.pem once it's stored.
3. Create the client in Keycloak
Section titled “3. Create the client in Keycloak”In your realm, open Clients → Create client, and choose the client type SAML. Then:
- On the client's Settings tab:
- Client ID: enter the entity ID that
startprinted. Keycloak uses the client ID as the service provider's entity ID. - Valid redirect URIs: enter the ACS URL that
startprinted. - Name ID format: choose email, and turn Force name ID format On.
- Sign assertions: turn it On.
- Client ID: enter the entity ID that
- On the Advanced tab, Assertion Consumer Service POST Binding URL: enter the ACS URL again.
- On the Keys tab, under "Signing keys config": turn Client signature
required On, and import Kindgi's certificate,
acme-sp-cert.pem. Keycloak can also read keys from a service provider's metadata URL. But Kindgi's metadata doesn't carry the certificate, so import it. - On the client's Client scopes tab: open its dedicated scope,
<client id>-dedicated. Then choose Add mapper → By configuration → User Property, with the Propertyemailand the SAML Attribute Nameemail.
4. Save the realm's metadata
Section titled “4. Save the realm's metadata”The realm's metadata is under Realm settings → General → Endpoints → SAML 2.0 Identity Provider Metadata. Save it to a file:
curl -fsS -o acme-idp-metadata.xml https://<keycloak-host>/realms/<realm>/protocol/saml/descriptor-fsSfails on an HTTP error, and prints only errors.-onames the file to save it to.<keycloak-host>is your Keycloak's address, and<realm>the realm's name.
5. Register it
Section titled “5. Register it”finish registers the client with its metadata and the signing key's name:
npx --yes @kindgi/cli@0.1 sso providers finish acme-saml --kind=saml --idp-metadata=@acme-idp-metadata.xml \ --domains=acme.test --sp-signing-key-ref=ACME_SAML_SIGNING_KEY --name="Acme SAML"--idp-metadata=@<file>reads the realm's metadata from the file. The@is required.--domainsare the email domains this provider is offered for.--sp-signing-key-refis the signing key's name from step 2.--nameis what the sign-in page's button says: "Sign in with Acme SAML".
Without --sp-signing-key-ref, finish refuses:
Error [identity-provider-invalid]: The identity provider wants signed sign-in requests (its metadata says WantAuthnRequestsSigned="true"): make a signing key and certificate, give IT the certificate, put the key (PEM) in the secret store, and set `spSigningKeyRef` to its nameKeycloak on a private network
Section titled “Keycloak on a private network”Kindgi refuses a Keycloak that the runtime reaches only on a private
address, unless the runtime's operator allows its origin with
KINDGI_AUTH_PRIVATE_IDP_ORIGINS
(Turn on sign-in):
Error [identity-provider-invalid]: http://127.0.0.1:18091/realms/acme is not a public HTTPS address (loopback): the deployment's operator can allow its origin with KINDGI_AUTH_PRIVATE_IDP_ORIGINS- Add people, and try it: only people you've added get in.
- Sign in to the console: what your people see.
- Change it, list it, remove it.