Closed Electrofenster closed 3 years ago
In the meantime I created a second little middleware (https://github.com/Electrofenster/jwt-verifier) which uses the access-token from yours and validate it with the introspection endpoint on each request and also my middleware adds the x-userinfo
-header as I suggestet it in #99 when accessing this service which uses your and mine middleware.
I should be able to add both...been a bit of a crazy week but when I get a little time I’m sure both requests can get knocked out.
@travisghansen any news on this? :)
Not yet but I’m getting close to putting it together! It’s a relatively easy change.
Maybe I’ll get this pushed out real quick for ya in the next
branch as I have some other additions that will take a little more time for my next release.
I'm looking into both your requests. Out of curiosity are you issuing an access token from keycloak directly? Or are you getting from eas after it does the authorization code flow and then using the token in some backend server-to-server process after parsing it from a header? I think I understand what you're doing here but want to make sure I understand.
Also, if you are indeed issuing an access_token direct from keycloak what the easiest way to do that not going through the authorization code flow (ie: client direct to keycloak)?
In this case I got the access_token from eas.
It would be very usefull if the OIDC plugin calls the introspection endpoint on every request to verify the user session ist still valid or to make sure that the user is still enabled or still exists. You can pass the accessToken to the introspection function of your client like this:
client.introspect(accessToken)
Also on this case, I'll use the userinfo-header to verify my logged in user on the backend.
And on your last question. Yes, I think this should be the easiest way. Below is a cURL example:
curl --request POST \
--url http://KEYCLOAK.tld/auth/realms/REALM/protocol/openid-connect/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data client_id=CLIENT_ID \
--data client_secret=CLIENT_SECRET \
--data username=USERNAME \
--data password=PASSWORD \
--data grant_type=password
I must have some configuration off. It seems every time I introspect the token in this context it comes back as false. Any ideas what configuration option I may have off?
I've pretty well got this buttoned up regardless. Should have something committed within the next day or so.
haha, the same problem I've got on my simple plugin as I developed it! :D But I don't remember what it was :/
The one thing is, that the access_tokens is only 5 minutes valid with default settings (in keycloak). Maybe you can test it with an the cURL from below to test the access_token on the introspection endpoint right after you got it. I think, you should get the introspection response.
I just think you should test it like this:
curl --request POST \
--url http://KEYCLOAK.tld/auth/realms/REALM/protocol/openid-connect/token/introspect \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data client_id=CLIENT_ID \
--data client_secret=CLIENT_SECRET \
--data token=ACCESS_TOKEN
when you get also
{ "active": false }
i think you keycloak is misconfigured
when you got the right response from introspection endpoint your access_token/session from eas is invalid. You can see it in keycloak under users -> your user -> sessions and check if there is the session from your client which you configured for eas to login to keycloak.
I figured it out..it was actually some bad code. This is really close to landing in next
branch to have you try it out.
Please see the doc here: https://github.com/travisghansen/external-auth-server/blob/next/PLUGINS.md#jwt
Update your image tags to next
and create a new config_token
with the appropriate settings. Let me know how it goes!
Well! Now it works! Thanks!
But I've one more little thing :D Could you add a setting to the jwt plugin to return a "401 Unauthorized" when the access_token is not valid? The redirect to the login could be very hard to figure out in a app when calling the expected endpoint.
Ah I should audit that a bit more closely. What was the exact error response/scenario that you got where you are expecting the 401 vs the 403?
UPDATE: doing a quick audit I think the only change that should be made is return a 401 when the token introspection check fails. The other scenarios should remain a 403.
Another change I could make is to auto detect the realm when oidc is enabled and set it to the token authentication endpoint of the issuer.
Thoughts?
New images are built in next
and ready for testing. It includes a proper return code for introspection failures and better logic around the realm
returned when oidc
is enabled.
On a semi-related note, I'm getting close to implementing the oidc
back-channel logout functionality. Any interest in helping test that and provide design input? Given the stateless design of eas
it provides a unique set of challenges associate with back-channel logout but I think I've got a solution that should do the trick and I'm ready to start implementation.
Yeah, I think it's a very good idea to additionally return a 401 when the token introspection check fails. (Usefull when using your plugin in an API as middleware) when accessing this with a browser I think the redirect to keycloak is more usefull.
I don't know why it shouldn't be usefull to auto detect the realm.
I tested your new image in my setup and it works very good.
Sure! Let me know when you need some help testing the back-channel logout functionality or when you may need some design input.
I’ve got several additions going on with logout scenarios currently:
eas
eas
The first 2 are done, now I just need to implement the 3rd and then it should be ready for testing.
The introspection of access_tokens directly from keycloak don't work or did I have a mistake? :)
I don’t understand the comment :(
if you got the access_token directly from keycloak e.g. with the cURL from above, does the jwt-plugin introspect the access_token on every request (when enabled)?
Oh, yeah it will introspect every request (unless introspection cache is turned in then whenever appropriate).
One question to the 401
As you use a invalid access_token you'll got a 201 with an redirect to keycloak login. Well that's not a good point when using the jwt-plugin in an API. Could you integrate a possible option to get a 401 unauthrorized instead. Currently I check if I could parse the HTML with JSON and when there is an error I require a new access_token with the refresh_token. That's not very good workflow. It's much easier when you can set an option to get a 401 unauthorized and refresh then the access_token.
I'm not sure I follow your workflow. The jwt
plugin never sends a 201 or any redirect...
I thought it was an 201 but it is 200 as status code, sorry. But I got as response any html.. I'll get this in my app:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" class="login-pf">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Sign in to game</title>
<link rel="icon" href="/auth/resources/zejp1/login/keycloak/img/favicon.ico" />
<link href="/auth/resources/zejp1/common/keycloak/web_modules/@fortawesome/fontawesome-free/css/icons/all.css" rel="stylesheet" />
<link href="/auth/resources/zejp1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/base.css" rel="stylesheet" />
<link href="/auth/resources/zejp1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/app.css" rel="stylesheet" />
<link href="/auth/resources/zejp1/common/key
also as header I'll get something like this:
{connection: close, set-cookie: AUTH_SESSION_ID=9e6146bb-18ca-41cc-b547-a306f690d2f4.keycloak-production-app; Version=1; Path=/auth/realms/game/; SameSite=None; Secure; HttpOnly,AUTH_SESSION_ID_LEGACY=9e6146bb-18ca-41cc-b547-a306f690d2f4.keycloak-production-app; Version=1; Path=/auth/realms/game/; Secure; HttpOnly,KC_RESTART=ey[...]
also when using cURL make sure you add the -L flag to follow redirects:
curl -k --request GET \
--url https://api.local/user/me \
--header 'Authorization: Bearer ACCESS_TOKEN' -L
then I'll get the same html from above. ;)
or use any invalid ACCESS_TOKEN like this:
curl -k --request GET \
--url https://api.local/user/me \
--header 'Authorization: Bearer INVALID_ACCESS_TOKEN' -L
I think some wires are getting crossed somewhere. It appears you have the service protected by both the jwt
and the oidc
plugins? Maybe send over a little diagram showing what services/clients/etc you have so I can better understand how you're getting that response.
If the service is solely authenticated with the jwt
plugin and the introspection fails you should never get a 200 or any html. Not only that, eas
never returns html...ever. So something is off somewhere.
LOL my mistake xD
I used both oidc
and jwt
:/ With only the jwt
'll get the 401
So all good now? Anything outstanding issues?
For now anything is working great!
Awesome! Thanks for the suggestion! It was a good one :)
All the new logout functionality has landed as well if you care to try out that. I haven't committed the updated doc just yet going into details though.
Just ping me when the docs are updated so I can test it. :)
I think it would be very grateful if the jwt plugin supports the introspection of access tokens to verify that the access token is still valid and authenticated via the introspection endpoint of the oidc provider.
I think it could be configureable as in the oidc plugin, so anyone who need this can activate it: