Dean Schulze
Dean Schulze

Reputation: 10303

How do I configure Keycloak and get a JWT with all steps done through the REST API?

I need to configure Keycloak running in Docker with a realm, a user with credentials, and a client and then get a JWT as in this blog post. If I use the UI as shown it works, but I need to automate all steps through the Keycloak REST API. When I do that all steps seem to work but getting a JWT fails.

I run Keycloak in Docker like this

docker network create keycloak-network

docker run --name mysql -d \
  --net keycloak-network \
  -e MYSQL_DATABASE=keycloak \
  -e MYSQL_USER=keycloak \
  -e MYSQL_PASSWORD=password \
  -e MYSQL_ROOT_PASSWORD=root_password \
  mysql:8.0.22

docker run -d -it \
  -e DB_VENDOR=mysql \
  -e KEYCLOAK_USER=admin \
  -e KEYCLOAK_PASSWORD=admin \
  --name keycloak \
  --net keycloak-network \
  -p 8080:8080 \
  jboss/keycloak:11.0.3

I obtain an access token from the master realm

POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=admin" -d "password=admin" -d "grant_type=password" -d 'client_id=admin-cli' "http://localhost:8080/auth/realms/master/protocol/openid-connect/token"|jq -r '.access_token'

Then I create my realm (named testrealm)

POST -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" -d @"${REALM_FILE}" "http://localhost:8080/auth/admin/realms"

Then I create a user with credentials:

POST "http://localhost:8080/auth/admin/realms/testrealm/users" --header 'Content-Type: application/json' -H "Authorization: Bearer ${ACCESS_TOKEN}" -d {"enabled":true,"username":"testuser","email":"[email protected]","firstName":"test","lastName":"user","credentials":[{"type":"password","value":"abc123","temporary":false}]}

I can see the new user in the UI and an entry in the new users credentials with Type password.

I create a client (named testclient)

POST -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" -d @"${CLIENT_FILE}" "http://localhost:8080/auth/admin/realms/testrealm/clients"

I get the necessary ids to modify the new client with

GET -H "Accept: application/json" -H "Authorization: Bearer ${ACCESS_TOKEN}" "http://localhost:8080/auth/admin/realms/testrealm/authentication/flows"

extracting the BROWSER_ID from the Alias browser and the DIRECT_GRANT_ID from the Alias direct grant.

I update the client changing the Access Type to confidential and with Authentication Flow Overrides for Browser Flow and Direct Grant Flow

PUT -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" --data @client.update.json "http://localhost:8080/auth/admin/realms/testrealm/clients/${clientId}"

where the data is

{                                                                               
    "publicClient": false,        
    "clientAuthenticatorType": "client-secret",                                            
    "authenticationFlowBindingOverrides": {                                                                 
        "direct_grant":"${DIRECT_GRANT_ID}",
        "browser":"${BROWSER_ID}"
    }
} 

I get the client secret with

GET -H "Accept: application/json" -H "Authorization: Bearer ${ACCESS_TOKEN}" http://localhost:8080/auth/admin/realms/testrealm/clients/${CLIENT_ID}/client-secret

At this point if I go into the UI it shows the same client secret that I get back and that the client Access Type is confidential and the Authentication Flow Overrides were set to browser and direct grant. Everything looks correct. The Keycloak server should now be configured the same as when done through the UI as shown in the post.

When I use the curl command as shown in the post to get a JWT

curl -L -X POST http://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

gives an error saying that https is required.

{"error":"invalid_request","error_description":"HTTPS required"}

But https is not required when the configuration was done through the UI. In fact all requests have been sent through http, not https.

Then using https

curl -L -X POST https://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

I get this error

curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

If I configure Keycloak through the UI the curl command works so I must have missed something when using the REST API. The Keycloak docs don't show this use case so they are no help here.

Does anyone know what I've missed when using the REST API?

Upvotes: 1

Views: 3527

Answers (1)

Jan Garaj
Jan Garaj

Reputation: 28626

Publish port 8443 of the Keycloak container. There will be https with self signed cert (so disable tls verification in your requests):

docker run -d -it \
 -e DB_VENDOR=mysql \
 -e KEYCLOAK_USER=admin \
 -e KEYCLOAK_PASSWORD=admin \
 --name keycloak \
 --net keycloak-network \
 -p 8443:8443 \
 jboss/keycloak:11.0.3

Keycloak will be available on https://localhost:8443. See Keycloak Docker HTTPS required

Upvotes: 2

Related Questions