Keycloak - invalid token when using nginx proxy - authentication

I’m trying to set up Keycloak using nginx as proxy.
The idea is to log in to web app using javascript adapter and then for each API request, nginx should ask Keycloak if token is valid (session could be revoked, etc.).
I’ve set it up without nginx locally - I have keycloak on my VM and I used Keycloak Gatekeeper to proxy API requests. It worked with no issues whatsoever.
Then, I deployed Keycloak and web app that uses js adapter on cluster and in nginx I proxied URLs required for login. Next, I configured auth module to call /auth/realms/cerulean-magnolia/protocol/openid-connect/token with grant_type=urn:ietf:params:oauth:grant-type:uma-ticket. There could be better endpoint to call but I’m always getting invalid_grant Invalid bearer token anyway.
Login works but when I try to use generated token, it becomes invalid and I can’t use it anymore.
I’ve set PROXY_ADDRESS_FORWARDING to true.
Any attempt of using this token ends up in getting:
{
"error": "invalid_grant",
"error_description": "Invalid bearer token"
}
If I would generate this token manually (via forwarded port) using password:
curl -L -X POST 'https://localhost:8141/auth/realms/cerulean-magnolia/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=lei' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'scope=openid' \
--data-urlencode 'username=...' \
--data-urlencode 'password=...' --insecure | jq
and then use this token to do:
http --verify=no -f https://localhost:8141/auth/realms/cerulean-magnolia/protocol/openid-connect/token grant_type=urn:ietf:params:oauth:grant-type:uma-ticket audience=lei-api response_mode=decision authorization:"Bearer ..."
It works fine. But if I use token generated via web app, I always get 401.
I’d be grateful for any help or hints.
Thanks in advance,
Patryk

Related

Keycloak X.509 authentication using proxy

I am trying to configure X.509 client authentication on the Keycloak 17.0.0 (Quarkus). I am using the quay.io/keycloak/keycloak:17.0.0 to deploy it in my Kubernetes environment.
I am running the Keycloak according the https://github.com/keycloak/keycloak/blob/main/docs/guides/src/main/server/reverseproxy.adoc:
/opt/keycloak/bin/kc.sh build --spi-x509cert-lookup-provider=nginx
/opt/keycloak/bin/kc.sh start-dev --spi-x509cert-lookup-nginx-ssl-client-cert=SSL_CLIENT_CERT
And I have the configuration of the X.509 client certificate authentication in the Browser and Direct Grant authentication flows, enabled in the authentication bindings, according the https://www.keycloak.org/docs/latest/server_admin/#_x509.
So expecting that the Keycloak will take the client certificate from SSL_CLIENT_CERT header and authenticate based on that.
However, trying to use the certificate to authenticate, I receive:
{
"error_description": "X509 client certificate is missing.",
"error": "invalid_request"
}
This is my curl:
curl http://localhost:8080/auth/realms/TEST/protocol/openid-connect/token \
-H "SSL_CLIENT_CERT: <cert_content>" \
-d "grant_type=password&username=&password=&client_id=CLIENT_ID&client_secret=CLIENT_SECRET"
There is a little documentation about how to do it behind the proxy in the Keycloak Quarkus version.
Anyone able to make it work?
1.) You need to use TLS, so you can't use http protocol for that - https is required. Ideal TLS config will have proper cert setup, otherwise curl will need --insecure.
2.) -H "SSL_CLIENT_CERT: <cert_content>" \ adds HTTP header, so that's is level 7 (OSI model), but TLS connection is level 4. So this is wrong.
Curl has another parameters --cert, --key for mutual (X.509) TLS. You should to have also proper data encoding, so in theory correct curl:
curl -s -X POST \
--cert /<path>/client-pem.crt \
--key /<path>/client-pem.key \
--data-urlencode "client_id=CLIENT_ID" \
--data-urlencode "client_secret=CLIENT_SECRET" \
--data-urlencode "grant_type=password" \
--data-urlencode "username=" \
--data-urlencode "password=" \
https://<keycloak-host>/auth/realms/TEST/protocol/openid-connect/token

Snapchat API User Auth VIA Redirect

Trying to authenticate with the snapchat API through CURL and I"m not sure what I'm doing wrong. I have tried the following:
curl -X GET \
-H "client_id={}" \
-H "redirect_url={}" \
-H "response_type=code" \
-H "scope=snapchat-marketing-api" \
https://accounts.snapchat.com/login/oauth2/authorize
through my terminal and I'm getting the following error:
curl: (3) URL using bad/illegal format or missing URL
zsh: command not found: -H
I'm fairly new to this so would appreciate any guidance. I was expecting to be redirected into a browser to authenticate and would be given a temp access token or refresh token
As per Snapchat documentation, you can actually pull the code by turning the request into a URL and the code will be displayed in the browser/address bar at the end of the redirect link after you authorise the app.
take bellow URL and fill in your details as required and follow it via your browser:
# Sample URL to redirect the OAuth users to - Single Scope
https://accounts.snapchat.com/login/oauth2/authorize
?client_id=4cxxxx8-1c33-xxxx-8798-xxxxxxxx
&redirect_uri=https://test.animalfarm.com/callback
&response_type=code
&scope=snapchat-marketing-api

cURL authentication with mod_auth_openidc and keycloak

I have an authentication server running Keycloak, and a Apache2 webserver with mod_auth_openidc to do OAuth2 authorization.
With browsers, I can successfully intercept access to protected resource to redirect user to Keycloak login page. After successful login, user will be redirected to the resource link.
With Postman, I can also retrieve access token JWT with password grant flow, then use the access token to access protected resource. The cURL code provided by postman indicates that the mod_auth_openidc_session cookie is also required.
Next, I try to do 2-stage cURL command in Linux CLI.
First I retrieve the access token using password grant flow as below. I initiated the cookie engine to capture session cookies given by mod_auth_openidc.
# RETRIEVE ACCESS TOKEN JSON
curl -L -b ./cookie.jar -c ./cookie.jar -d 'client_id=CLIENT_ID' -d 'client_secret=368127b1-1ee0-4f3f-8429-29e9a93daf9a' -d 'username=USERNAME' -d 'password=PASSWORD' -d 'grant_type=password' 'https://AUTH_SERVER:PORT/auth/realms/REALM/protocol/openid-connect/token
# PARSE ACCESS TOKEN
access_token=`echo $response|jq '.access_token'|cut -d\" -f2`
Next, with the access token bearer in header and cookie jar file, I try to access to the protected resource.
curl -b ./cookie.jar -c ./cookie.jar --insecure -L -X GET 'https://RESOURCE_SERVER:PORT/protected_content' --header "'Authorization: Bearer "$access_token"'"
However, I still got redirected to the Keycloak login page, and the session cookie is not recorded in the cookie jar file.
Here is the recorded cookie jar file with sensitive info redacted/replaced.
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_[AUTH_SERVER] FALSE /auth/realms/master/ TRUE 0 KC_RESTART eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2Y2ZiNjYwOC1kMTlhLTQwZGUtOWJiYS04NzcxOTkzZTIwMWUifQ.eyJjaWQi[REDACTED]4aHhkVDBGZmhBZEVTSm8iLCJub25jZSI6IndTYXNYOWhGeGIxd1hKakNrS2FLMXVadVRGX3ZOZzRGVUZnMTJyYXFWbVkifX0.53645krpwlFnJ09cHAcZhNCci-DhGigu4soN5CVsZQ0
#HttpOnly_[AUTH_SERVER] FALSE /auth/realms/master/ TRUE 0 AUTH_SESSION_ID_LEGACY 6a23b139-05ba-4d22-b9e3-9ae857074814.[AUTH_SERVER]
#HttpOnly_[AUTH_SERVER] FALSE /auth/realms/master/ TRUE 0 AUTH_SESSION_ID 6a23b139-05ba-4d22-b9e3-9ae857074814.[AUTH_SERVER]
#HttpOnly_[RESOURCE_SERVER] FALSE / TRUE 0 mod_auth_openidc_state_XGEq0YKJAwSt8hxdT0FfhAdESJo NVc9Mk1FmN[REDACTED]lydKVtOw0iL-Y9iZMjzcUinutFPn74rmVvI_ERV3C8Wn1Euio8pID0jEAmu9NEfY_MEeuzOzqe6w7I20HZUNQHX0uh_vXR8
Can anyone tell me what I did wrong in the 2-stage cURL authentication/authorization process?
You have single quotes inside double quotes when setting Authorization header. This means instead of expect Authorization: Bearer token server is getting 'Authorization: Bearer token'. You can check the contents of your headers by using verbose -v option.
Following command should work as expected:
curl --header "Authorization: Bearer $access_token" -b ./cookie.jar -c ./cookie.jar --insecure -L -X GET https://RESOURCE_SERVER:PORT/protected_content'
Optionally, if you need double qoutes around token use following:
--header "Authorization: Bearer \"$access_token\""
Side note: In order not to overwrite existing cookies in cookie.jar, use different file name to store cookies from the request to authorized file.

Keycloak include permission into the access token along with the roles

I have been working on setting up authorization using keycloak, and have set up specific roles and permissions based on resources and but the JWT access token contains only the details about the roles and not the permission assigned to the user.
I want the access token to include permission details and have tried the methods on Keycloak documentation:
1) Using permission ticket cannot generate the ticket using
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission
it shows:
{
"error": "invalid_bearer_token",
"error_description": "Could not obtain bearer access_token from request."
}
and thus cannot generate the RPT and get details of the permissions.
Also tried using the entitlement API.
2) Using entitlement API:
curl -X GET \
-H "Authorization: Bearer ${access_token}" \
"http://localhost:8080/auth/realms/hello-world-authz/authz/entitlement/${resource_server_id}"
I tried using postman and it shows 404 Not Found..
Can anyone show me the correct procedure to include the permission in the access token or generate the RPT correctly.
Keycloak provides a discovering document for Authorization Services. You can obtain from following url.
curl -X GET http://localhost:8080/auth/realms/{realm}/.well-known/uma2-configuration -H "Authorization: Bearer ${access_token}"
here localhost and 8080 are for keycloak host and port
error says token you are using is not valid for the client.
I was able to get RPT using below command
curl -X POST http://localhost:8080/auth/realms/${realm}/protocol/openid-connect/token -H "Authorization: Bearer ${access_token}" --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" --data "audience={resource_server_client_id}" --data "permission=Resource#Scope"
Keycloak responds to the client with the RPT

How can I obtain a Mule ARM registration token to be used to register a server into AMC

I was reading at
https://anypoint.mulesoft.com/apiplatform/anypoint-platform/#/portals/organizations/ae639f94-da46-42bc-9d51-180ec25cf994/apis/38784/versions/127446/pages/182856
because I want to automate Anypoint Runtime Manager enablement on lots of servers.
My plan is to use REST to get the proper registration token to be used to register a server into AMC. There are directions on the page:
To register a server you must first authenticate against the Anypoint Platform Authentication Manager and get an authentication token, with this token you need to obtain a registration token to be used to register a server into AMC.
I understand the first part and can get the authentication token, but I can't find a reference to how to get the registration token.
How can I get this token?
Thanks!
have you seen the Obtain the Server Registration Token part in the documentation?
take a look here, if you want to obtain a registration token by calling the REST API. There is a API endpoint called /servers/registrationToken
You can also get a registration token with the new anypoint-cli v2.x. This will combine several REST API calls for you. The command is:
runtime-mgr server token
You can type this in the interactive shell, or add this to the end of a stand-alone call from your favorite scripting environment. For example, if you have created a profile with your ANYPOINT_USERNAME, ANYPOINT_PASSWORD, and ANYPOINT_ORG, and ANYPOINT_ENV, you can then call:
anypoint-cli runtime-mgr server token
You can find the docs and installation instructions here: docs.mulesoft.com/runtime-manager/anypoint-platform-cli#runtime-mgr-server-token.
If you want to do this directly with the REST API, you'll have to make several calls:
POST a core services access_token from
anypoint.mulesoft.com/accounts/login
with the username and password in the BODY as a JSON object.
curl -X POST \
anypoint.mulesoft.com/accounts/login \
-H 'content-type: application/json' \
-d '{
"username":"yourUserName",
"password":"yourPassword"
}'
Store the response as a variable (let's call it {{access_token}}.
Copy this access_token in the header for every other API call: Key: Authorization, Value: bearer {{access_token}}
Obtain or store the organization ID in which you want to register the server. There's several ways to do this. The value is available via a GET request to
anypoint.mulesoft.com/accounts/api/me
curl -X GET \
anypoint.mulesoft.com/accounts/api/me \
-H 'authorization: bearer aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
You might want to use the JQ libraries to parse the organizationID from this JSON response.
Get the environment ID for the environment in which you want to register the Mule runtime (server) from a GET request to:
anypoint.mulesoft.com/accounts/api/organizations/{{organizationId}}/environments
curl -X GET \
https://anypoint.mulesoft.com/accounts/api/organizations/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb/environments \
-H 'authorization: bearer aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' \
-H 'content-type: application/json'
Make a GET request to
anypoint.mulesoft.com/hybrid/api/v1/servers/registrationToken
With the headers X-ANYPNT-ORG-ID and X-ANYPNT-ENV-ID set:
curl -X GET \
anypoint.mulesoft.com/hybrid/api/v1/servers/registrationToken \
-H 'authorization: bearer aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' \
-H 'x-anypnt-env-id: cccccccc-cccc-cccc-cccc-cccccccccccc' \
-H 'x-anypnt-org-id: bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'
This will return a registration token.
Then use this registration token with the amc_setup -H command
amc_setup -H {{registration_token}} Server-Name