Where does jwt.io get the public key from JWT token? - jwt

I was decoding a JWT token via jwt.io (in the Debugger section) to see Headers, Payload. Surprisingly, it also verified, and I could see it (jwt.io debugger) is able to retrieve the public key as well.
So my question is: Does JWT token provide the public key as well as part of the JWT token?
I am pasting part of it (can't paste full due to security reasons, will be truncating part of the actual JWT token)
F3cy5jb21cL2V1LXdlc3QtMV9ZckVRYjY5Z1giLCJleHAiOjE2MDE2Mzg4OTMsImlhdCI6MTYwMTYzNTI5MywidmVyc2lvbiI6MiwianRpIjoiNmI2YmZiNmYtY2M0MS00N2Q5LWI0YzYtOTBmOGFmNWM2MjQ1IiwiY2xpZW50X2lkIjoiMTM0MWxxa3N1ZmUwbm1vaW9kdnRjc2t2cWIifQ.RtKfz54uBgSZ1gc4KRPjzL4dPe5AbH2YMJu-DDvIxBzgMjqT9q4ApGzcWYB62-MgDUf-F_hK0kF9eIwAi9fARhp 0HGGnyiuydW_our6zE3EphLvXQByTDY5xzOUuSvt7WbDZWeSfpHcjrBttRSJAPOsZ2gInafKjZgWKyGL4vJB9swEhOMSSpTQDGWKenJCyp4emhe8E4XGzYTo9WEb-Wqg6sI__LrusDNd917FaocPKBxA
Decoded messages (again truncated)
Headers
{
"kid": "cJ0PzkBXPyjX7FM67jcOECIY=",
"alg": "RS256"
}
Payload:
{
"sub": "13lqs0moiodvtcskvqb",
"token_use": "access",
"scope": "example.com/Manage",
"auth_time": 1601293,
"iss": "https://cognito.eu.amazonaws.com/",
"exp": 1601638,
"iat": 10353,
"version": 2,
"jti": "cc1-47d9-b6-5c6245",
"client_id": "nmodvtcb"
}
In there, can see the Public key (truncated)
-----BEGIN PUBLIC KEY-----
QEFAAOCAQ8AMIIBCxmf9bakWk
556KYmIZB+Sy1ftkkGa4qlUsmRvcG2Hll+7HBWp1ao6MVLskjdaaKg8iH1Iz4DKG
lgqT/ndwhoxvTBuvm0X2CZoNzZn4S8wDTr78m/S/YegZRhv6y58gkiKSEmbbC/g5
Bp+AF88NwBvLm1jdd
-----END PUBLIC KEY-----
Where from the debugger in jwt.io is retrieving the public key? I am not able to understand this.

The token contains the issuer (iss) of the token and the key id (kid), which identifies the public key that is needed to verify the signature
With this information, jwt.io can find the public key in form of a JWK (JSON Web Key) on a JWKS endpoint (/.well-known/jwks.json), to verify the token. A JWKS (JSON Web Key Set) contains an array of JWKs, the link shows an example.
According to the cognito documentation, this mechanism is used, when you use the Amazon user pool to authenticate your users.
Providing keys via a jwks endpoint is a standard mechanism which is also used by other providers, e.g. Microsoft Azure.

I've been trying to understand that myself too. If you open developer tools and see requests made by jwt.io when you paste the token in the debugger page you'll see it makes additional requests.
In my token the iss was:
"iss": "http://localhost:8080/auth/realms/myrealm"
hence jwt.io added the standard path /.well-known/openid-configuration and made XHR request to
http://localhost:8080/auth/realms/myrealm/.well-known/openid-configuration
Where it found a lot of information in json and among them there was jwks_uri
{
...
"jwks_uri": "http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/certs",
...
}
And then there was another XHR request to the above url and response was jwks.
Having that public key the jwt.io could verify the token. At least that's what I think happens.

Related

Here API returns Unrecognized Kid Null error

This is my cURL request
curl https://geocode.search.hereapi.com/v1/geocode?q=5%20Rue%20Daunou%2C%2075000%20Paris%2C%20France -H "Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXX"
This is the response
{"error":"Unauthorized","error_description":"Token Validation Failure - unrecognized kid null"}
I am not sure what is going on. I tried different access keys. I generated new ones. But keep getting the same error.
The "Access Key ID" is not quite the token you need to send in the Authorization header, which is why you get a "Token Validation Failure".
The "Access Key ID" is however one of the credential parameter that you need, in order to generate the OAuth tokens, the other parameter being the "Access Key Secret".
If you didn't save the Access Key Secret already, go to your HERE Account Project Management Space and make sure to download the credential file:
In the credential file, pay attention to the last three lines:
here.access.key.id = redacted
here.access.key.secret = redacted_redacted_redacted
here.token.endpoint.url = https://account.api.here.com/oauth2/token
Then, we can use Postman to generate the OAuth tokens:
Open Postman and create a new request.
Method POST, url: https://account.api.here.com/oauth2/token
Go to the Auth tab and select:
Type: OAuth 1.0
Add auth data to Request Headers (probably the default choice)
Signature Method: HMAC-SHA256
Consumer Key: put the here.access.key.id value
Consumer Secret: put the here.access.key.secret value
Go to the Body tab and select:
x-www-form-urlencoded
Key: grant_type, Value: client_credentials
Send the request. You should receive an access token. That one should work with your curl request.
Auth tab
Body tab
Note
For the record, the following, not using OAuth but an "API key" to be found under the REST section as well, also works:
curl https://geocode.search.hereapi.com/v1/geocode?apiKey=<REST-API-KEY>&q=5%20Rue%20Daunou%2C%2075000%20Paris%2C%20France
However the Geocode API Reference does not document the apiKey authentication, unlike other HERE API e.g. Routing, and I would not recommend it besides for occasional experiments with curl requests.
I found a very simple solution. I removed the Authorization header and added the "apiKey" query parameter to my URL.
For example:
https://revgeocode.search.hereapi.com/v1/revgeocode?48.2181679%2C16.3899064&lang=en-US&apiKey={TOKEN}

Retrieve email from token | #auth0/auth0-spa-js

I have been trying to upgrade to #auth0/auth0-spa-js from auth0-js, although I could not get my head around reading an email from a token which in turn was obtained from await useAuth0().getTokenSilently()
I use jwt.io to decrypt the token, and this is what I get in the payload:
{
"iss": "https://TENANT_NAME.auth0.com/",
"sub": "auth0|SOME_HASH",
"aud": [
"https://API_IDENTIFIER",
"https://TENANT_NAME.auth0.com/userinfo"
],
"iat": 1563699940,
"exp": 1563786340,
"azp": "SOME_OTHER_HASH",
"scope": "openid profile email"
}
When I was using auth0-js I could just add scope: "openid email" to new auth0.WebAuth({...}) and voilà – I had email and email_verified in the payload of the decrypted token.
I believe the 2 part series of tutorials were not able to answer my question, and retrieving the token from a hooked getTokenSilently() inside my Apollo configuration was also a challenge on its own. I like the redirect implementation for SPA, however. Please, can you suggest a proper way to include email and email_verified in the token's payload?
UPDATE
By reading this piece of documentation on api-tokens I understood the token I am getting from getTokenSilently() is called the access token. I have been using ID tokens in all of my requests' headers till this day, and that was probably a bad approach:
In the OIDC-conformant pipeline, ID Tokens should never be used as API tokens.
Also, the documentation says:
The token does not contain any information about the user except for the user ID (located in the sub claim).
In many cases, you may find it useful to retrieve additional user information. You can do this by calling the /userinfo API endpoint with the Access Token.
Which I did by following the shell example. I have sent the request with my access token and magically got an object containing the user's profile information from Auth0's Custom API.
We got close, what is an algorithm converting the "sub" into user profile residing inside Auth0's Custom API which I can implement for my backend written in ruby?
Yes, as you mention, ID tokens should not be used as API Tokens. They have a different usage (and you don't want your API Token to be too big, because you send it in each request's headers).
To get the user email, you can just fetch the UserProfile given in the ID Token. To achieve that, you just have to call getUser instead of getTokenSilently.
If you want more infos about the user, you have 2 ways to fetch user info:
You use the Auth0 Management API to fetch the user infos, based on the user id (in the sub claim of the ID Token) and using this API endpoint. In Ruby, you can just use a basic HTTP request.
You use a rule to always include specific fields in the ID Token. For example, you can include user_metadata and app_metadata in your ID Tokens. That way, you can use it without additional API call. To achieve that, you will need a specific Rule that will run when ID Tokens are generated (more general API doc).
An example rule that would add all user_metadata and app_metadata to the ID token would be:
function (user, context, callback) {
const namespace = 'your_url_namespace_just_for_cosmetic_but_required/';
context.idToken[namespace + 'user_metadata'] = user.user_metadata;
context.idToken[namespace + 'app_metadata'] = user.app_metadata;
callback(null, user, context);
}
And you will have the info in your ID Token for your frontend to use.
For the record, more rules examples on this hard-to-find page.

When i try to authenticate oauth1 rest api returnse Invalide_signature error

I have to access the Snoobi api for analytics.
They are providing differnt steps to authenticate the Snoobi api through Oauth1. they are
Snoobi have two api call for the authentication the first request i can access https://api.snoobi.com/oauth/requesttoken?oauth_callback= and get request url.
Bu in case of second request https://api.snoobi.com/oauth/accesstoken is return invlid_signature.
I can't figuare out this issue....
My sample site is Sample site with these authentication did by DDO oauth1 library.
The authentication steps are given below.
Step 1: Request token
The request token endpoint for Snoobi API is at:
https://api.snoobi.com/oauth/requesttoken
The request is made with with HTTP POST to URL:
https://api.snoobi.com/oauth/requesttoken?oauth_callback=<your application callback, URL encoded>
Authorization headers
The OAuth parameters are sent in HTTP Authorization header
Field Value
oauth_consumer_key Your applications consumer key (40 chars)
oauth_nonce Randomly generated string in ASCII format. Subsequent requests with same nonce and timestamp combination will be ignored. Recommendation is to use 64-bit random number.
oauth_signature Request signature
oauth_signature_method HMAC-SHA1″ or ”PLAINTEXT
oauth_timestamp Unix timestamp
oauth_version 1.0
Example authorization header (line breaks added for readability):
Authorization: OAuth oauth_consumer_key=”2cab9166c5180256f4788a7669c181c84bec61ee”\,oauth_signature_method=”HMAC-SHA1″,\oauth_nonce=”7524122124ddba21d644043.98235934″\
,oauth_timestamp=”1306239517″,\
oauth_version=”1.0″,\
oauth_signature=”kP6LwV%2FJfs9YcG4irDJuoP271uU%3D”
On successful request /oauth/requesttoken returns the request token and token secret. These come in parameters ”oauth_token” and ”oauth_token_secret”, respectively. Also the authentification url is provided in the response parameter ”authentification_url”. The URL is something akin to: https://api.snoobi.com/oauthgrant.php and your application should redirect the user’s browser to this address. If user is not already logged in to Snoobi, he will be prompted to do so.
After login, user gets to the view where they can grant the access to the application:
Snoobi's OAuth grant view
Once user clicks the Grant button he gets redirected to your callback url, with oauth_token and verifier added as url parameters:
http://youapp.com/callback.php?oauth_token=66393e59b10dddc112a8d1cbca9f9559d01127a1&verifier_token=051dd4f45b791957d8c12b83b9810365bbb50e63
Step 2: Access tokens
Now that your application has acquired the request token, secret and verifier, it is ready to call the access token end point to get the permanent access tokens.
The access token endpoint is:
https://api.snoobi.com/oauth/accesstoken
Authorization headers
Field Value
oauth_consumer_key Your applications consumer key (40 chars)
oauth_nonce Randomly generated string in ASCII format. Subsequent requests with same nonce and timestamp combination will be ignored. Recommendation is to use 64-bit random number.
oauth_timestamp Unix timestamp
oauth_version 1.0
oauth_token Your request token
oauth_signature Signature
Authorization: OAuth oauth_verifier=”ff17678750b3ca5b5263babee610bb9f47f7a1b6″,\oauth_consumer_key=”2cab9166c5180256f4788a7669c181c84bec61ee”,\oauth_signature_method=”HMAC-SHA1″,\
oauth_nonce=”2556773534ddb9f01d00518.41306989″,\
oauth_timestamp=”1306238721″,\
oauth_version=”1.0″,\
oauth_token=”f3a4eb25c1267f28d5de54e89a78db48f4d7ed30″,\
oauth_signature=”%2F9y%2BtMdCZk1uRYawXsfWHb%2BPmig%3D”
On success, the accesstoken service returns the access token and secret in fields: oauth_token and oauth_token_secret.
When I try the auth verifier changed to post form data then it grants the access. I thought the documentation is wrong defines that.

How to secure a Jersey REST call in this case

The problem i am facing is that clicking on F12 on Chrome Browser , i could see all the Rest Calls which are made to fetch the data
For example , one of the REST API call is
(When clicked on the above link , it fetches the data )
This is my front code consists of Jquery
function displaymarketupdates() {
var updatedon = "";
var html = '';
var t = "",
$.ajax({
type: "GET",
url: e,
crossDomain: !0,
dataType: "json",
timeout: 17e3,
async: !0,
cacheResults: !1,
cache: !1,
contentType: "application/json",
charset: "utf-8",
beforeSend: function() {
$(".loadingWrapformarketupdates").show()
},
complete: function() {
$(".loadingWrapformarketupdates").hide()
},
success: function(response) {
},
error: function(t, e, a) {
$(".loadingWrapformarketupdates").hide()
}
}).done(function() {
})
}
And this is my service
#Path("/fetchallvalues")
public class FetchAllValues {
public FetchAllValues() {}
private final static Logger logger = Logger.getLogger(FetchAllValues.class);
#GET#Produces("text/plain")
public Response Fetch_all_values() {
PreparedStatement fetch_all_pstmt = null;
ResultSet fetch_all_Rset = null;
Connection dbConnection = null;
ResponseBuilder builder = Response.status(Status.NOT_FOUND);
final JSONArray fetch_array = new JSONArray();
final String inputsql = "select * from all_values";
try {
dbConnection = DBConnection.getDBConnection();
fetch_all_pstmt = dbConnection.prepareStatement(inputsql);
fetch_all_Rset = fetch_all_pstmt.executeQuery();
while (fetch_all_Rset.next()) {
====
}
Response.status(Status.OK);
builder = Response.ok(fetch_array.toString());
} catch (Exception e) {
e.printStackTrace();
logger.error("Error description", e);
} finally {
try {
DBConnection.close(fetch_all_pstmt, fetch_all_Rset);
} catch (Exception e) {
logger.error("Error description", e);
}
try {
DBConnection.close(dbConnection);
} catch (Exception e) {
logger.error("Error description", e);
}
}
return builder.build();
}
}
Could you please let me know how to secure the REST CALL in this case
You cannot hide an URL from a Browser's network monitoring. It is meant to be displayed so that it can be inferred that what is happening when you hit a button or click something.
Securing a REST Jersey call is a totally different thing. That means you do not want people to see your data that you are going to pass. As correctly mentioned by Martingreber that if you call this URL on HTTPS that may help you encrypt data that you send across the servers. Or securing a REST call actually means you provide some kind of authentication to it . Like Basic , Hashing like MD5, Token based Authentication like JWT.
The only thing that you can do to hide explicit details from your browser that runs your JavaScript is minify your script . But still your URL remains exposed as many times as it is called by someone who fiddles with the F12 key on Chrome to see what's going on. One more thing can be if you are concerned about your main service call, and don't want to expose that , then just PROXY it using some service, which you are already doing . But by no means, you can avoid your URL being getting displayed, when someone calls it.
In your case fetchAllValues service is fetching the data and exposing it to anybody on the web who clicks it, but that can be prevented if you authenticate the service, like the minute i click that URL, it asks me for a password! Then i cannot access it. A very simple way to authenticate this service would to call a Filter or an Interceptor just before the request to ask for username and password like credentials.
I hope you got the point. Hope this helps :)
You will always be able to see the URL that is being processed. Still, you could obfuscate the Service Endpoint to hide the purpose of the service itself, e.g. #Path("/XYZ")instead of #Path("fetchallvalues")
If you want to hide the data that is being transmitted between the client and the server, so noone can read it, simply use https. Depending on your webserver (Jetty, Tomcat) you will have to configure it differently, still you will need a ssl certificate for your domain, which you can get here for example: https://letsencrypt.org
If you want to secure your webservice, so it can't be used by anyone, but only by specific users, you might want to give Spring Security a try: User authentication on a Jersey REST service
This is a problem that needs some smart hacks to fix it.
In the hyperlinked stackoverflow page, you will get an example of how to make a SOAP request from client side JavaScript.
SOAP request from JavaScript
Now here's the plan:
In the server side, we have a random number generator, which generates a random number in short intervals, say 5 minutes.
The random number generator will be exposed as a SOAP service and it will produce the random number generated.
From the client side, we will invoke the SOAP random generator service (refering to the stackoverflow page mentioned above) and get the generated random number as the response. We will invoke the service from a JS function which will be fired when your page is loaded (onLoad). So, now we have the random number at the client side.
Then, we pass the random number as a path param in the GET request URL of the REST call and fire the GET request.
In the server side, once the Rest GET request is received, we check if the number received as path param is the same number that is generated in the server side.
If the numbers match, then we give the required response, else do not send the response.
Here we are trying to introduce an unique key, which is the random number generated at the server side. This unique key, when passed as the path param of the Rest GET request URL, serves as an identity of the origin of the Rest GET call. For someone who wants to invoke the Rest Api by referring to the Network Tab of the Chrome Dev console, will not get the unique key for a long time ( as it is refreshed/regenerated after every 5 minutes). Thus the hacker will not be able to use the Rest Api for a long duration. Also, since we are transporting the unique key (the random number) from the server to client side using SOAP, it is not possible for the hacker to get it from the Chrome's developer console.
Hope this approach helps!
Unfortunately, there is nothing you can do to prevent the client from inspecting the requested URL. But you always can require credentials to access your API endpoints.
Authentication in REST APIs
In REST applications, each request from the client to the server must contain all the necessary information to be understood by the server. With it, you are not depending on any session context stored on the server and you do not break the REST stateless constraint, defined by Roy Thomas Fielding in his dissertation:
5.1.3 Stateless
[...] communication must be stateless in nature [...], such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
When accessing protected resources (endpoints that require authentication), every request must contain all necessary data to be properly authenticated/authorized. And authentication data should belong to the standard HTTP Authorization header. From the RFC 7235:
4.2. Authorization
The Authorization header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response. Its value consists of
credentials containing the authentication information of the user
agent for the realm of the resource being requested. [...]
In other words, the authentication will be performed for each request.
Basic authentication
The Basic Authentication scheme, defined in the RFC 7617, is a good start for securing a REST API:
2. The 'Basic' Authentication Scheme
The Basic authentication scheme is based on the model that the client
needs to authenticate itself with a user-id and a password for each
protection space ("realm"). [...] The server will service the request only if it can validate
the user-id and password for the protection space applying to the
requested resource.
[...]
To receive authorization, the client
obtains the user-id and password from the user,
constructs the user-pass by concatenating the user-id, a single
colon (":") character, and the password,
encodes the user-pass into an octet sequence,
and obtains the basic-credentials by encoding this octet sequence
using Base64 into a sequence of US-ASCII
characters.
[...]
If the user agent wishes to send the user-id "Aladdin" and password
"open sesame", it would use the following header field:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
[...]
Token-based authentication
If you don't want to send the username and the password over the wire for every request, you could consider using a token-based authentication. In this approach, you exchange your hard credentials (username and password) for a token which the client must send to the server in each request:
The client sends their credentials (username and password) to the server.
The server authenticates the credentials and generates a token.
The server stores the previously generated token in some storage along with the user identifier and an expiration date.
The server sends the generated token to the client.
In every request, the client sends the token to the server.
The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
If the token is valid, the server accepts the request.
If the token is invalid, the server refuses the request.
The server can provide an endpoint to refresh tokens.
Again, the authentication must be performed for every request.
The token can be opaque (which reveals no details other than the value itself, like a random string) or can be self-contained (like JSON Web Token).
Random String: A token can be issued by generating a random string and persisting it to a database with an expiration date and with a user identifier associated to it.
JSON Web Token (JWT): Defined by the RFC 7519, it's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64. The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server. You won't need to persist JWT tokens if you don't need to track them. Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To find some great resources to work with JWT, have a look at http://jwt.io.
In a token-based authentication, tokens are your credentials. So the tokens should be sent to the server in the standard HTTP Authorization header as described above.
Once you are using Jersey, you could have a look at this answer for more details on how to implement a token-based authentication in Jersey.
HTTPS
When sending sensitive data over the wire, your best friend is HTTPS and it protects your application against the man-in-the-middle attack.
To use HTTPS, you need a certificate issued by a certificate authority such as Let’s Encrypt, that claims to be a free, automated, and open certificate authority.

Getting Invalid signature error while invoking FITBIT rest API

I have registered in FITBIT.
I am making a request to fitbit api(POST /oauth/request_token) with consumer key. I have referred https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API
My request is:
POST /request_token HTTP/1.1
Host: oauth
Authorization: OAuth realm="https:/api.fitbit.com/oauth/request_token",oauth_consumer_key="XXXXXXXXXXXX",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1399958922",oauth_nonce="H8xxW0",oauth_version="1.0",oauth_signature="80M1tag6%2FYk2JV%2FQdQ%2BucxxDrLA%3D"
Cache-Control: no-cache
I am getting invalid signature error with below json object:
{
"errors": [
{
"errorType": "oauth",
"fieldName": "oauth_signature",
"message": "Invalid signature: 80M1tag6/Yk2JV/QdQ+ucxxDrLA="
}
],
"success": false }
We have Consumer Key and Consumer Secret Key. Don't have Token Secret at this stage. please give me a solution to get this API working.
Thanks,
Kalyan
Like WestDiscGolf mentioned, you need to make sure that your callback URL matches the callback URL in the application you are writing. Usually when you sign up for a developer account to access API's, they ask for a callback URL, and the callback URL has to match what you put in when you request an access token.
If you're getting an invalid signature error, though, then the callback URL probably isn't the issue. You need to make sure that the signature matches exactly what they specify in the API documentation. Signatures can be tricky, and there are a number of libraries that are available to help with that. I use Java primarily, and for Java the Scribe library is great (https://github.com/fernandezpablo85/scribe-java).