API user creation and role assignment

I need help creating a user and assigning a role to that user through bash (yes, bash…)

I already have the code to get my auth token and I can create the user, my problem is that to assign the role to the user, I need the user-id… I can see the user-id is returned on the output headers of the curl command to create the user but I’m not sure whats the best way to grab that id from this output.

I’m hoping there is a way to pull the user-id if I pass the user-name and realm to the API OR it would be great if I can create the user AND assign it a role in the same API call.

I’m trying to not grep/sed/awk the output (which I know I could send the output of the call to a file and parse through them).

You could create a default role for new users, for example: How can I restrict registrating automatically by IdP

If you are working with json then you should check out: jq

Also see (a curl and jq example): wait-for-container-to-exit.sh

@Robinyo thanks for the prompt reply.

I need to accomplish the following 2 tasks through API calls utilizing bash:

  1. Create a user and assign it a temporary password (I have this done).
  2. Assign a specific role to the user created in step #1.

Where i’m having issues is in the assigning a role to the user that was just created. The docs state that I need the user-id and the name of the role that I wish to apply, but how can I get the user-id programmatically?
When I create the user in step #1, I can see in the headers a line called “Location” which has the user-id for the user that was just created.

I was hoping there was a one-liner that would allow to create the user and assign the role in just one call…if not, then how can I accomplish this programmatically?

Here is the output of 1 run of the script:

./add_user.sh --username puuuhplease
+ [[ 2 -gt 0 ]]
+ [[ --username == *\-\-* ]]
+ v=username
+ export username=puuuhplease
+ username=puuuhplease
+ shift
+ [[ 1 -gt 0 ]]
+ [[ puuuhplease == *\-\-* ]]
+ shift
+ [[ 0 -gt 0 ]]
+ test -z puuuhplease
+ source ../.env
++ SSL_ENABLED=false
++ KEYCLOAK_URL=http://localhost:8080
++ KEYCLOAK_REALM=demo
++ tr -dc _A-Z-a-z-0-9
++ head -c16
++ echo
+ RANDPASS=RpdiRQ4Brtcuf6wH
++ curl -s http://localhost:8080/auth/realms/master/protocol/openid-connect/token --data 'username=changeme&password=changeme&grant_type=password&client_id=admin-cli'
++ jq -r .access_token
+ TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEdlRSVW9iWUVFNGxEVnNvS2t6U3JLUnZBcG9aNGpXbDdZS1J2djlUQnIwIn0.eyJleHAiOjE1OTI4NzUxOTMsImlhdCI6MTU5Mjg3NTEzMywianRpIjoiOTVlOTY2NjMtYzBhYi00Zjc3LTkzMWYtZDFhYjUzOGRhM2UyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjU4OGRiMTM5LWRjNDctNDM1NC05MDNmLTM1Mjg2ZGJiODU2YyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJiNjllZTdhOS04MzljLTRmZTUtYmM5Mi04NmVmY2M0ZGViNmUiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJjaGFuZ2VtZSJ9.CIw1I9e6UI2QStemZ0JTRxptfKHMs2OYjzHeUWnBkLew0EqHTdNq7gKvpq_s_V9dqjYrfCnOInfh9vD0r_bnqdiobixFI0mKu12He77RxvsQNBapNXNOMJaAEntVpZ-VY8-jhB_M0YFg0iP5xf593NABl0l2xyXW9-vlJ7ltFOlOzEaDJVSlI3FPwiPHodVIeuTsZMrXGU4KV6GJXe1cJefDwYtorrUY2Dq2MGvYs64mFgAzOlGZGznmLpHfT1AU0927zSnvCbfORUFJQsn5QuFI-fHRcQKcmX_oV4mPPhB4rvgUI4aYugofBzmQ0myZ9gg0ToiMY-GHxeSLbvKB0w
++ generate_payload
++ cat
+ curl -v http://localhost:8080/auth/admin/realms/demo/users -H 'Content-Type: application/json' -H 'Authorization: bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEdlRSVW9iWUVFNGxEVnNvS2t6U3JLUnZBcG9aNGpXbDdZS1J2djlUQnIwIn0.eyJleHAiOjE1OTI4NzUxOTMsImlhdCI6MTU5Mjg3NTEzMywianRpIjoiOTVlOTY2NjMtYzBhYi00Zjc3LTkzMWYtZDFhYjUzOGRhM2UyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjU4OGRiMTM5LWRjNDctNDM1NC05MDNmLTM1Mjg2ZGJiODU2YyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJiNjllZTdhOS04MzljLTRmZTUtYmM5Mi04NmVmY2M0ZGViNmUiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJjaGFuZ2VtZSJ9.CIw1I9e6UI2QStemZ0JTRxptfKHMs2OYjzHeUWnBkLew0EqHTdNq7gKvpq_s_V9dqjYrfCnOInfh9vD0r_bnqdiobixFI0mKu12He77RxvsQNBapNXNOMJaAEntVpZ-VY8-jhB_M0YFg0iP5xf593NABl0l2xyXW9-vlJ7ltFOlOzEaDJVSlI3FPwiPHodVIeuTsZMrXGU4KV6GJXe1cJefDwYtorrUY2Dq2MGvYs64mFgAzOlGZGznmLpHfT1AU0927zSnvCbfORUFJQsn5QuFI-fHRcQKcmX_oV4mPPhB4rvgUI4aYugofBzmQ0myZ9gg0ToiMY-GHxeSLbvKB0w' --data '{
  "username":"puuuhplease",
  "email":"",
  "firstName":"",
  "lastName":"",
  "enabled":"true",
  "credentials":[{
      "type": "password",
      "temporary": "true",
      "value": "RpdiRQ4Brtcuf6wH"
  }]
}'
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /auth/admin/realms/demo/users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.61.1
> Accept: */*
> Content-Type: application/json
> Authorization: bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEdlRSVW9iWUVFNGxEVnNvS2t6U3JLUnZBcG9aNGpXbDdZS1J2djlUQnIwIn0.eyJleHAiOjE1OTI4NzUxOTMsImlhdCI6MTU5Mjg3NTEzMywianRpIjoiOTVlOTY2NjMtYzBhYi00Zjc3LTkzMWYtZDFhYjUzOGRhM2UyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjU4OGRiMTM5LWRjNDctNDM1NC05MDNmLTM1Mjg2ZGJiODU2YyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJiNjllZTdhOS04MzljLTRmZTUtYmM5Mi04NmVmY2M0ZGViNmUiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJjaGFuZ2VtZSJ9.CIw1I9e6UI2QStemZ0JTRxptfKHMs2OYjzHeUWnBkLew0EqHTdNq7gKvpq_s_V9dqjYrfCnOInfh9vD0r_bnqdiobixFI0mKu12He77RxvsQNBapNXNOMJaAEntVpZ-VY8-jhB_M0YFg0iP5xf593NABl0l2xyXW9-vlJ7ltFOlOzEaDJVSlI3FPwiPHodVIeuTsZMrXGU4KV6GJXe1cJefDwYtorrUY2Dq2MGvYs64mFgAzOlGZGznmLpHfT1AU0927zSnvCbfORUFJQsn5QuFI-fHRcQKcmX_oV4mPPhB4rvgUI4aYugofBzmQ0myZ9gg0ToiMY-GHxeSLbvKB0w
> Content-Length: 211
> 
* upload completely sent off: 211 out of 211 bytes
< HTTP/1.1 201 Created
< Connection: keep-alive
< X-XSS-Protection: 1; mode=block
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< X-Content-Type-Options: nosniff
< Location: http://localhost:8080/auth/admin/realms/demo/users/fdb4567f-bdab-40b0-9b4b-d89d292c4d3f     <===== This is what I need to capture
< X-Frame-Options: SAMEORIGIN
< Content-Length: 0
< Date: Tue, 23 Jun 2020 01:18:53 GMT
< 
* Connection #0 to host localhost left intact