does keycloak wildfly adapter care for "Issued At" Claim - jwt

I wonder if, keycloak wildfly adapter care for "Issued At" Claim.
So imagine, a keycloak standalone and a wildfly server have a small time difference, and keycloak creates a JWT token where iat (issued at) claim
seems to be a few milliseconds in future (at least in comparison to the time at the server running wildfly) ...
What will happen? The token will be accepted or not?

Your token will be accepted, iat is used for the comparaison with the not-before property. By default not-before is set to 0 and iat>not-before and the token will be valid but not-before can be set to now (or future) and than the iat is needed to validate the token.

Related

Disable Keycloak user quickly when account is disabled on identity provider

When an user account is disabled on a connected IdP, how do I ensure the account is blocked as soon as possible on Keycloak? At the moment, the “disabled” user is able to continue using my SPA because Keycloak continues to refresh the access token without speaking to the external IdP.
One of the critical features required by my partners when using SSO is that they have control over their users’ access to my application. At the moment if the user was logged into my SPA, they can continue using it for about 24 hours. I would hope to cut that time down to 5 minutes, the lifetime of the access token.
The external IdP is Google. I have tried using both Keycloak’s builtin Social provider for Google as well as setting up a SAML app in Google and user-defind SAML provider in Keycloak. I’m using Keycloak v9 but can upgrade if necessary.
Is there a recipe to achieve my goal? What options do I need to set in the Keycloak client and SAML provider?
Many thanks!
The approach could be as follows. The resource server will need to do the checking with the IDP, not Keycloak.
Enable the option to Store Tokens and Read Stored Tokens in the IDP settings.
Assign users the broker/read-tokens role.
On the resource server, decide on a frequency to check whether the user has been disabled on the IDP. Be aware of each IDP's token introspection's endpoint. Each time the API is consumed:
First of course verify the access token as usual.
If it's time to verify against the IDP, call the Keycloak API with the access token to retrieve the IDP's access token.
The Keycloak endpoint is: https://{domain}/realms/{realm}/broker/{idpid}/token
Call the IDP's token introspection endpoint to validate the IDP access token.
Act accordingly if the IDP responds that the token is not valid. Respond with 401 and ensure that the Keycloak access token can't be used again. Maybe the end_session_endpoint or revocation_endpoint, not sure.
Token validation endpoints:
Google: https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={access_token}
AuthO: https://{tenant}.eu.auth0.com/userinfo
MS Azure: doesn't exist, good luck with that!

OpenIdConnect verify jwt from OpenId Provider

We have a web application Vuejs(front) and a api Nodejs(back).
We delegate authentication to a third party OpenIdProvider.
Users login in the front and get and access token.
This access token contains:
nbf : the time before which the JWT MUST NOT be accepted for processing.
iat: the time at which the JWT was issued.
exp: time expiration of token
In my case when i log in at 11am i have:
nbf: 11:00 am
iat: 11:00 am
exp: 11:30 am
In each request from VueJS to NodeAPI, the access token is passed and verified by the back.
I verify jwt token like this:
jwt.verify(token, publicKey, { algorithms: ['RS256'], audience: process.env.OP_CLIENT });
The publicKey is read from the OpenIdProvider jwks_uri and the audience is my provider client id.
The problem is that the time on my nodejs server is late, is it : 9:00
So when i use verify i get this error message:
NotBeforeError: jwt not active
at /var/www/app/node_modules/jsonwebtoken/verify.js:143:21
at getSecret (/var/www/app/node_modules/jsonwebtoken/verify.js:90:14)
at Object.module.exports [as verify] (/var/www/app/node_modules/jsonwebtoken/verify.js:94:10)
at async authUser (/var/www/app/src/helpers/openid.js:87:19) { date: 2021-07-27T09:00:51.000Z }
I read that I could ignore the notBefore option but the problem remains the same on the validity period of the token ?
because with a time difference between the issuing time of the provider and the time on my server it distorts the verification.
what do you recommend ? is this the correct way to verify my token from a provider?
Your code looks pretty standard - similar to this code of mine.
The times used should be UTC times, so the preferred resolution is to ensure that the UTC time on the server is correct - eg by running a simple OS command such as date -u in bash.
Note also that there is an option called clockTimestamp that can be passed into the Auth0 library.
This will not help if the server clock is badly wrong though. If an IT administrator runs the server, it is their job to ensure that the system clock is correct.
Thanks Gary !
Finally i set
ENV TZ="Europe/Paris" in my docker file and my backend is now at the good timezone.
I also added the deactivation of the notBefore check to avoid problems if it has a few minutes of lag
jwt.verify(token, publicKey, { ignoreNotBefore:true, algorithms: ['RS256'], audience: process.env.OP_CLIENT });
Our server is running inside a docker container in a swarm cluster.
So i think, i have to set correctly the good UTC timezone in my deploy stage

Keycloak authentication: how can a external user get an token without exposing client secret

I have a query about how keycloak is supposed to be working with client without GUI access.
Basically I have:
A keycloak server configured with a realm, clients(Access type confidential) and Users
A server application with a GUI that also provide API, secure with keycloak (client, user, blablabla)
This is kind of working already as I am able to log on the GUI, have the redirect, etc..
Even accessing the APIs works well, when I have access to a GUI: I log on my UI, follow the redirect and get my UI to display the token. The the human (to differentiate the user from an application), can use the token in any API client.
In this context the user never sees the client secret, which is instinctively the right way. (note that I am very opened to people telling me my instinct is wrong!)
What I am NOT able to do so far is to find the way a server application (without GUI) can get a valid token?
The authorization_endpoint, as far as I understand it, requires both the client id and the client secret) to get a token, which I would rather avoid: I don't think giving my client secret to all my "customers" is the proper way to do it.
Alternatively I could create an API on my client that woudl ask for user credential and ask for the token in its behalf, but that would expose the clients credentials to my application, which is against the whole concept!
I tried setting my client Access type as public, but when I use the API call below I also get a error:
POST /auth/realms/realmname/protocol/openid-connect/tokenAPI
'grant_type=client_credentials'
'client_id=client_id'
'username=username'
'password=password'
{
"error": "unauthorized_client",
"error_description": "Public client not allowed to retrieve service account"
}
Would anyone know how this is supposed to be done ?
Thanks in advance.
Max
(...) A server application (without GUI) can get a valid token... typically using the Client Credentials flow.
But we would define in this case a dedicated Client for your server (client?) application to authenticate against. The returned token (not bound to a specific user) will serve for authorizations on allowed applications (i.e. your classic GUI or API clients).
So, basically you should (in very short):
define a specific confidential Client in your Keycloak
add the desired applications (or other Clients) to the Client Scope(s). Those you want to authorize transitively from this Client.
authenticate against this Client with Client Credentials flow (given the token endpoint, client id, credentials, scope)
ensure that you are authenticating through TLS and that parameters are included in request body (and not in headers - for enhanced privacy)
further harden security of your Client(s)
When you do not want anymore this particular server (client?) application to access your applications, you can change the corresponding "authentication" Client's secret/credentials or simply delete it.
"I don't think giving my client secret to all my "customers" is the proper way to do it."
You are right and the proposed method above strictly avoids that. Each customer would have its own credentials.
EDIT
(adding more details)
By performing as above, you would end up with the following scheme:
Flow Keycloak Server
C/S app. or Customer X <--- Client Creds ---> Auth. Client X
--- Access Token ---> Appl. Client <--> Appl. Server
C/S app. or Customer Y <--- Client Creds ---> Auth. Client Y
--- Access Token ---> Appl. Client <--> Appl. Server
Browser users <--- Standard ------> Appl. Client <--> Appl. Server
Note: this is not a detailed flow chart. Arrows mostly show relationships here.
Finally, please note that the terminology may differ a little here, but the proposed method is basically the same that Google uses. So you may aswell take some inpiration from there:
https://developers.google.com/identity/protocols/oauth2
I just had the same problem some weeks ago
In my case, I have a backend API and a frontend application that the users can use.
Eventually, I can't share the client_secret to the frontend application.
So here is my solution:
On keycloak, create a client (ex front_end_client) with grant type public
This client is going to be used by the frontend application to authenticate users using implicit flow (with PKCE will be more secure)
On keycloak, create a second client (On the same REALM as the first client) with grant type confidential, this client is going to be used by the backend API
Now, this is how it works:
Frontend app authenticate users and get the access token (Using the font_end_client)
The frontend app sends this token for every request to the backend
Backend app verify this token, and can retrieve permissions from it

Keycloak token validation flow

When a request with the bearer token hits a microservice, does microservice talk to keycloak to validate the token for each request?
Is traffic "Step 5" configurable via keycloak adapter?
No, that would make too many requests. In initialization phase microservice loads public key and signing algorithm from Keycloak’s well known config page. On each request microservice checks the signature of the bearer token.
Access token lifespan should not be too long and that is how you force your frontend to periodically go to Keycloak and refresh the bearer.
If you run your microservice, every time you send a request to an api after adding the token in the logs you will see "Loaded URLs from http://localhost:8080/auth/realms/{realm-name}/.well-known/openid-configuration". Upon clicking this link you will see that there are a set of URLs present here, endpoints for token generation, userinfo etc.,there are endpoints for getting the certs and signing keys as well via which the signing key of the token is verified.
(This will only happen if keycloak properties are defined in application.properties/application.yml)
Step 5 will happen on using Keycloak adapter (Choice of adapter given in keycloak documentation)

how to change openid connect idtoken's iss

I deployed wso2 IS 5.3.0 in docker. I set it up for openid connect authentication. I tried to have kubernetes to work with it for authentication. But it turns out to have problem with iss field in idtoken. The payload part of the token looks like below after decode:
{"exp":1487335376,"sub":"admin","azp":"Dibo_uMHzySCIxrf55uvMGWjGEUa","at_hash":"_8q5TmtJRsdEj4V_dL4-Zg","aud":["Dibo_uMHzySCIxrf55uvMGWjGEUa"],"iss":"https:\/\/localhost:9443\/oauth2\/token","iat":1487331776,"acr":"urn:mace:incommon:iap:silver"}
By openid connect spec, the iss field is expected to be "https://192.168.1.123:9443/oauth2/oidcdiscovery/" in my case. How can I do to change the iss value of default in idtoken?
Thanks
You need to set things up before running the wso2 IS server of its first time.
Set IDTokenIssuerID in identity.xml as below first. Then run IS server. The settings will be picked up.
<IDTokenIssuerID>${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/oidcdiscovery/</IDTokenIssuerID>