What does didn't find publicKey for kid error mean in Keycloak - keycloak

What does didn't find publicKey for kid error mean in Keycloak
2021-07-24T09:36:22,992 INFO [http-nio-5555-exec-9] o.k.a.KeycloakDeployment: Loaded URLs from https://foo.baz.com/auth/realms/sso/.well-known/openid-configuration
2021-07-24T09:36:23,156 ERROR [http-nio-5555-exec-9] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8
2021-07-24T09:36:23,181 ERROR [http-nio-5555-exec-9] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8
2021-07-24T09:36:23,410 ERROR [http-nio-5555-exec-3] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8
2021-07-24T09:36:23,412 ERROR [http-nio-5555-exec-1] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8
2021-07-24T09:36:23,415 ERROR [http-nio-5555-exec-1] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8
2021-07-24T09:36:23,417 ERROR [http-nio-5555-exec-3] o.k.a.r.AdapterTokenVerifier: Didn't find publicKey for kid: a7GiJ8syCz3UYPMlVKmfWb9tfPYLxbz_j5xWOniokg8

The service is verifying the integrity of a JWT and it is failing.
The verification is done by recalculating the signature based on the JWT's header and body and comparing it with the signature that is presented in the JWT. If the calculated signature and the one that is in the JWT match, the JWT surely comes from the expected party and no 3rd party had modified it (although a 3rd party could see it!).
For generating the signature, in the case of the most common method, RS256, a key is required. This key should only be obtained from the issuer of the token to guarantee the correctness of the verification process. For this reason, the token only holds a reference id for that key in the kid field.
The default certs' URL in your case should be:
https://foo.baz.com/auth/realms/sso/protocol/openid-connect/certs
The response should hold a similar key array like the response of the Google's cert endpoint:
{
"keys": [
{
"kty": "RSA",
"alg": "RS256",
"e": "AQAB",
"n": "nQPB_WqGG18pjGSFGQwRLcZkcRojHHweN27mV1oTNeeH2quq5NvWibLEheiukVP60nXcGNpkP_PaycYahEfvAnJGLX_IscGAOJ67WWFs4M8wXHH6g2mTnalcAYgmpN1QDMVgz4NcWISXNTR-8FZfWgFN4LDZgK4f0wXOaJlh_Bzh-plPLJQUXyY7mZTEVsH8X3wg2fvV0Hxj_HudjgFlYPdDri1Oi4vI0wiKV4nJCRZ-INH3OIvPl-05WVjZ-XTSXdNjLNx35NM2Npcrr9VpZ8Xeg7pr0wjamqd_07xfEAdtFxsN6Ay6Ecz3k0onQP-6SLRCGLrMAxifziivmmafCQ",
"use": "sig",
"kid": "7f548f6708690c21120b0ab668caa079acbc2b2f"
},
{
"n": "psh4_fDTsNZ1JkC2BV6nsU7681neTu8D37bMwTzzT-hugnePDyLaR8a_2HnqJaABndr0793WQCkiDolIjX1wn0a6zTpdgCJL-vaFe2FqPg19TWsZ8O6oKZc_rtWu-mE8Po7RGzi9qPLv9FxJPbiGq_HnMUo0EG7J4sN3IuzbU--Wmuz8LWALwmfpE9CfOym8x5GdUzbDL1ltuC2zXCaxARDnPs6vKR6eW1MZgXqgQ6ZQO9FklH_b5WJYLBDmHAb6CguoeU-AozaoVrBHgkWoDkku7nMWoetULtgBP_tYtFM8zvJ9IDD6abZM0jl-bsHIm3XFz0MgAJ9FmPti9-iShQ",
"kty": "RSA",
"alg": "RS256",
"kid": "3df0a831e093fae1e24d77d47834405f95d17b54",
"e": "AQAB",
"use": "sig"
}
]
}
In a normal case, the kid from the JWT can be found in this response, so, with the value of the corresponding "n" field, the signature can be calculated. But in your case, the kid is not there.
Common problems in this case:
a new key was introduced in the keycloak realm and the kid is referencing the old one
the URL of the openid-configuration is not correct
there is a caching layer in front of keycloak, so the response of openid-configuration is not up to date
a compromised/3rd party modified token
refs: AdapterTokenVerifier
jwt.io

Related

How to access Namespaced JWT Claims in AWS HTTP API Gateway Request Mapping

I'm trying to set up HTTP integration in AWS API Gateway v2 (aka HTTP API). In my config, I have a native JWT authorizer and want to append one namespaced JWT access_token claims to HTTP request headers.
As long as claims as simple name such as sub or iss this is working fine with the following mapping syntax:
append:header.simple = append:$context.authorizer.claims.simple
However, some of my claims are namespace with an https://namespace/ prefix (is a requirement from Auth0 and cannot be changed). This is where mapper syntax is falling short for me.
Say my input JWT is like this:
{
"aud": "my.dev.api",
"azp": "CCCC",
"exp": "1610606942",
"https://my.ns/account_no": "100368421",
"iat": "1610598342",
"iss": "https://mytenant.auth0.com/",
"scope": "openid profile email account:admin",
"sub": "auth0|user-id"
}
How can I map namespaced claim https://my.ns/account_no?
I tried $context.authorizer.claims['https://my.ns/account_no'] with no luck. Here is the terraform setup I use:
resource "aws_apigatewayv2_integration" "root" {
api_id = aws_apigatewayv2_api.api.id
integration_type = "HTTP_PROXY"
connection_type = "INTERNET"
description = "This is our GET / integration"
integration_method = "GET"
integration_uri = "http://${aws_lb.ecs_lb.dns_name}"
passthrough_behavior = "WHEN_NO_MATCH"
request_parameters = {
"append:header.account_no" = "$context.authorizer.claims['https://my.ns/account_no']" <-- FAILING HERE
}
}
Error I'm getting in terraform and dashboard is the same:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: $context.authorizer.claims["https://my.ns/account_no"]]
Thanks for your assistance.

JWT validation failed: Could not find matching key in public key set for kid

I'm generating a JWT using google-auth-library-nodejs by providing the credentials through env variables, similar to the sample code from here.
const credentials = JSON.parse(JSON.stringify(env.service_account.credentials));
const client = auth.fromJSON(credentials);
const url = 'my_url';
const token = await client.fetchIdToken(url);
When using that token later on for authentication, the request fails because of the following error:
JWT validation failed: Could not find matching key in public key set for kid=7da7843e8637d669bc2a12622cede2a8814d11b1
https://jwt.io/#debugger-io confirms that the kid of the generated JWT is indeed 7da7843e8637d669bc2a12622cede2a8814d11b1, however, the private key id in the json is 6bd5b5d36f9a4225bd814ff3d6909d95e23e0793.
Here's the json
'{
"type": "service_account",
"project_id": "project_id",
"private_key_id": "6bd5b5d36f9a4225bd814ff3d6909d95e23e0793",
"private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXX\n-----END PRIVATE KEY-----\n",
"client_email": "my_service_account#project_id.iam.gserviceaccount.com",
"client_id": "REDACTED",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my_service_account%40project_id.iam.gserviceaccount.com"
}
Should the kid match the privat_key_id?
client_x509_cert_url provided in the question above was not the right x-google-jwks_uri. It actually has to be https://www.googleapis.com/oauth2/v1/certs.
After changing the URI, the kids match.
If anyone has a clue why that is, it would be much appreciated.

Wiremock json stub for https calls

I wanted setup https call as json configuration stub in wiremock.
What are the additional configuration need top provide?
I have below json config
{
"id": "177a103d-85e4-4688-acd6-acc8a97ce085",
"name": "provider_rest_push",
"request": {
"url": "/user/profile",
"method": "POST",
"bodyPatterns": [
{
"equalToJson": "{\"type\":\"011\".....}",
"ignoreArrayOrder": true,
"ignoreExtraElements": true
}
]
},
"response": {
"status": 200,
"body": "{\"result........."}",
"headers": {
"Cache-Control": "must-revalidate,no-cache,no-store",
"Content-Type": "application/json",
"Server": "Jetty(8.1.15.v20140411)"
}
},
"uuid": "177a103d-85e4-4688-acd6-acc8a97ce085",
"persistent": true,
"insertionIndex": 5
}
Above perfectly work for http but NOT for https:
I get below when changed to https
[WARNING] Illegal character 0x16 in state=START for buffer HeapByteBuffer#35a693b9[p=1,l=262,c=8192,r=261]={\x16<<<\x03\x01\x01\x01\x01\x00\x00\xFd\x03\x03\x87\xEb\xEb\x8b0\xB7\x14...\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x033t\x00\x00>>>ding: gzip, defla...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
[WARNING] badMessage: 400 Illegal character 0x16 for HttpChannelOverHttp#72ab37c7{r=0,c=false,a=IDLE,uri=-}
2020-03-17 12:53:14.631 Request received:
0:0:0:0:0:0:0:1 - POST /user/profile
I referred this answer but not sure the password for the second step in the first answer
i.e.
Import certification into keystore
keytool -import -trustcacerts -alias mock -file localhost.crt -keystore identity.jks
According to http://wiremock.org/docs/https/ you need to configure the httpsPort. This is done at startup, not at runtime so it seems that you can't use the JSON API for that. If you're running the standalone version of Wiremock you can provide the port by specifying the environment variable https-port, have a look at http://wiremock.org/docs/running-standalone/ for that.
In either case, make sure you take note of the certificate requirements at the bottom of http://wiremock.org/docs/https/.

Invalid signature while signing JWT with RSA Keys using https://jwt.io/

Hi I am testing some api through POSTMAN.
REGISTRATION API- It takes public key and stores in server.To get public JWK Key I am using https://mkjwk.org/. It generates a key with public and private key. Below is the key generated:
{
"kty": "RSA",
"d": "HgP6c8xA3D_-8DKgSk3fQ_FZuPj2RNSFE5NLfGz3GJjkyt9fzOPztNObQmLZ2EoJzPrYL8ljk-1mKGIr5Ma1n4TPX_kQ9JErq9wNyhMUTykQ8PqjMuxmUpddn43RZ27VPjvUvHMulk5hPBFv0uH3LnDsM1xn34icj40y4zcRTYXwixqDgj74Ua_9aaZwPXX06Ykc3vzC5M4F5JP4ZjuLTFjmM8jxzJpu4JNDncXwhHE5Xtv3t1oezXTHNZdRzyTTtFLOeyYeLt5WWM-y549du3hsUtvgNnJ4JTS4uEHEonDMW8CV5ZzoQE8F81LT5Q84coYzOjVlzC50w7st3vLFYQ",
"e": "AQAB",
"use": "sig",
"kid": "sdk291",
"alg": "RS256",
"n": "0h5Pgw32t3NtODVj1UrNkk90RytZBz2T09JBEo1NwYtw0T7NM3SrFsleLK8e_DknE26rB8EXD2T1YmUSuseuWvW-LPdwbk--SrKo8Df1H5ff5hDZYJ_x-NPDJ_ZmoY7r2U83aGY-DubilufhDf6icB2auTGxBvVylAl5Jdf7UBsjHAWrgWAtFFvnkbcaUk1O7ZA8nS4Iyk4l8vVsoUOJCSRrysceObAOG-EYj1UfdzOBZsuSj5Usst6ebRjF9M1VNJOLcvm6EiAqazayyqbsengnA-hqUGRgfd6HXXZ5Hg4BU_srPVBXrVmx81azHY5lRUdZr_Khtw4O0Zy3UIwMWw"
}
I am only sending public key portion to this API and this API Works fine.
GETTING ACCESS TOKEN USING JWT API- This takes a JWT which will be created with some claims . And we have to sign it with RSA Public and private key. I am facing problem in signing the JWT.
To get text/pem version of public and private keys from above JWK, I am using https://8gwifi.org/jwkconvertfunctions.jsp . This gives us below public and private key.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0h5Pgw32t3NtODVj1UrN
kk90RytZBz2T09JBEo1NwYtw0T7NM3SrFsleLK8e/DknE26rB8EXD2T1YmUSuseu
WvW+LPdwbk++SrKo8Df1H5ff5hDZYJ/x+NPDJ/ZmoY7r2U83aGY+DubilufhDf6i
cB2auTGxBvVylAl5Jdf7UBsjHAWrgWAtFFvnkbcaUk1O7ZA8nS4Iyk4l8vVsoUOJ
CSRrysceObAOG+EYj1UfdzOBZsuSj5Usst6ebRjF9M1VNJOLcvm6EiAqazayyqbs
engnA+hqUGRgfd6HXXZ5Hg4BU/srPVBXrVmx81azHY5lRUdZr/Khtw4O0Zy3UIwM
WwIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICHgIBAAKCAQEA0h5Pgw32t3NtODVj1UrNkk90RytZBz2T09JBEo1NwYtw0T7N
M3SrFsleLK8e/DknE26rB8EXD2T1YmUSuseuWvW+LPdwbk++SrKo8Df1H5ff5hDZ
YJ/x+NPDJ/ZmoY7r2U83aGY+DubilufhDf6icB2auTGxBvVylAl5Jdf7UBsjHAWr
gWAtFFvnkbcaUk1O7ZA8nS4Iyk4l8vVsoUOJCSRrysceObAOG+EYj1UfdzOBZsuS
j5Usst6ebRjF9M1VNJOLcvm6EiAqazayyqbsengnA+hqUGRgfd6HXXZ5Hg4BU/sr
PVBXrVmx81azHY5lRUdZr/Khtw4O0Zy3UIwMWwIBAAKCAQAeA/pzzEDcP/7wMqBK
Td9D8Vm4+PZE1IUTk0t8bPcYmOTK31/M4/O005tCYtnYSgnM+tgvyWOT7WYoYivk
xrWfhM9f+RD0kSur3A3KExRPKRDw+qMy7GZSl12fjdFnbtU+O9S8cy6WTmE8EW/S
4fcucOwzXGffiJyPjTLjNxFNhfCLGoOCPvhRr/1ppnA9dfTpiRze/MLkzgXkk/hm
O4tMWOYzyPHMmm7gk0OdxfCEcTle2/e3Wh7NdMc1l1HPJNO0Us57Jh4u3lZYz7Ln
j127eGxS2+A2cnglNLi4QcSicMxbwJXlnOhATwXzUtPlDzhyhjM6NWXMLnTDuy3e
8sVhAgEAAgEAAgEAAgEAAgEA
-----END RSA PRIVATE KEY-----
I am taking these keys and going to https://jwt.io/ , then updating Header and payload with my required values.
Header:
{
"alg": "RS256",
"typ": "JWT"
}
Payload :
{
"iss": "e9064e3cb1cc445cb2095f3dc675b4gf",
"sub": "e9064e3cb1cc445cb2095f3dc675b4gf",
"aud": [
"southgate"
],
"iat": 1543469348,
"nbf": 1543469348,
"exp": 1543517174,
"jti": "a6fb0873-8653-4923-be47-e53e0acabb35",
"schemas": [
"urn:x:y:v1"
],
"ten": "myTen"
}
After this when I sign the JWT including public and private key from above, It doesnt generate JWT token and gives "INVALID SIGNATURE" error. SO I am not able to generate the signed JWT which is needed as input for this 2nd API.
PS- I am in testing phase now. So I havent wrote any code to test the api and using only online generator tool.
Please let me know how I can solve the issue.

Orion context broker global instance token

I want to publish some data on the Orion context broker global instance and I have requested a token as referred at Quick start guide. When I continue coding (java client) next day I got:
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: java.net.SocketException: Unexpected end of file from server
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155)
at com.sun.jersey.api.client.Client.handle(Client.java:652)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509)
at publishers.fiware.OrionClient.getEntities(OrionClient.java:23)
at FiwareTest.main(FiwareTest.java:11)
Caused by: java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:792)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:789)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:253)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:153)
... 6 more
So I requested a new token and worked again.
A token generated that way has an expiration time? How much?
Do I have a way to get a non expiring token?
According with OpenStack Keystone default configuration, tokens expires after 1 hour:
http://docs.openstack.org/juno/config-reference/content/section_keystone.conf.html
# Amount of time a token should remain valid (in seconds).
# (integer value)
#expiration=3600
You can renew it by getting another one:
http://developer.openstack.org/api-ref/identity/v3/index.html?expanded=#token-authentication-with-unscoped-authorization
POST /v3/auth/tokens HTTP/1.1
Host: test.ttcloud.net:5001
Content-Type: application/json
X-Auth-Token: {{user-token}}
{
"auth": {
"identity": {
"methods": [
"token"
],
"token": {
"id": "{{user-token}}"
}
}
}
}