i am working on an authentication system that has access and refresh tokens and JWT and JWKS. my problem is that i don't know what is the functionality of JWKS. what is the functionality of JWKS in a authentication system that is working with JWT and refresh token and access token? what are public and private keys in this system? does JWKS need to connect to database?
Do you mean JWKS or a JWKS endpoint?
JWKS is JSON Web Key Set - a JSON notation for sharing public keys which are used to verify the signature of a signed JWT.
JWKS endpoint is an endpoint exposed by the Authorization Server from which you can obtain a JWKS.
Whenever you need to work with a content of a JWT (e.g. so you have an API which receives the JWT and need to perform authorization decisions) you should verify the signature. In order to verify it you need a public key, which corresponds to the private key used by the Authorization Server to sign the JWT. This public key can be obtained in different ways (e.g. you can hard code it in your API) and getting it from a JWKS endpoint is one valid way. If you have an option of reading public keys from a JWKS endpoint I would recommend to use it - this simplifies greatly key management in your system. Whenever you need to rotate keys, you just change them in the Authorization Server. It's especially useful if you do not control the Authorization Server - then you don't have to worry about keys rotation at all.
You can have a look at the second part of this free course: OpenID Connect in Details (requires email registration). The JWKS topic is covered there.
Related
I am looking at the examples of JWT tokens in Node.js, and the verify function. My question is, where does this publicKey come from in verify(token, publicKey)? What is the flow?
The client (one of my users) has a client library installed on their computer/server, for making requests to my app myapp.com. In the myapp.com server, I call verify(token, publicKey). In the client library I generate the token using privateKey. The question is, how does the client get this private key generally? (i.e. is heroku login downloading a private key under the hood for making JWT requests, sort of thing?). And how do you fetch the public key? My understanding is, the client would download a private key, and our server would store the public key. Then given you have the public key and token, just call verify(token, publicKey). But how do you get the public key for the token on the server generally? Is the server storing one public key per private key disseminated to the client installed libraries?
The way I've usually seen JWTs used, there is only a very small number of trusted issuers, often only one, and the tokens are used as bearer tokens. In many cases, the issuer and the verifier are the same. In other cases, the verifier trusts one identity provider (e.g. Google) and fetches the public key from a https URL (example).
In your case, you could act as both the issuer and verifier:
You (the server) would generate one key pair.
Your API servers would trust JWTs signed by this key (and they'd only have the public key, since they only need to verify them).
An authentication/management server would have the private key, would authenticate your user, and issue them a JWT.
The client would never handle any keys, they'd simply store the signed JWT, and pass it as a bearer token when making a client request.
This is e.g. the approach described here as the approach used by GitHub. In this case, the issuer and verifier both belong to you. This approach is the easiest for both you (you can trust the content of the JWTs once you've verified the signature), and the client (they're just dealing with an opaque API key and don't need to deal with the complexities of JWTs at all).
A possible alternative approach could be:
A key pair is generated and the public key is associated with the account. This can be done in multiple ways (see below), but the end result is the same: The client has a private key, and your server knows the corresponding public key and which user it is associated with
When making a request, the client creates a JWT, signs it with its private key, and includes their user name in the token (e.g. in the iss and or sub field).
Your server takes the token, extracts the user name, looks up the public key associated with the account in the database, and validates the token.
This approach is used e.g. by Google Cloud for service account authentication.
Step 1 above can be done in two ways:
You authenticate the user, generate a key pair, associate the public key with the account, and let the user download their private key (via https of course). While it's generally considered somewhat bad form to generate keys for someone else (because you get to see a key that you don't need to know and you have to send it over the network), it's a lot easier, and Google is doing just this.
The user generates and stores the key pair. You authenticate the user, the user uploads the public key, you associate it with the account.
Either way, if you go with the "user signs a JWT" approach, you likely will want to provide client libraries, or at least code examples. Note also Google's requirement that the tokens must be short-lived, enforced by treating long-lived tokens as invalid. Without this rule and enforcement, what will happen is that many client developers will be annoyed about your complicated solution, manually sign a token that is valid forever on his laptop, and then use it as a bearer token.
heroku login actually doesn't use JWTs at all. It retrieves and stores an OAuth Bearer Token. This is most comparable to the first approach (client never handles any private keys, just gets an opaque blob, which happens to be a JWT that you can verify). The difference between a non-JWT token and a long-lived JWT is that your API servers have to look up the meaning and validity of the regular token in a database, whereas the JWT directly tells you the user identity, and possibly permissions and other attributes that you included when issuing it.
I have been reading about OAuth 2.0 Authorization Code flow to protect APIs in microservices architectures but I dont understand how an access token issued by the Auth Server is supposed to protect an API hosted in another server.
Is that same access token also kept in the API and when the client tries to access it with the access token issued by the Auth Server, the API checks if contains it? If so, does that mean that the access token is sent both to client and the protected API in the authentication process?
I hope to have explained my problem well. Thanks in advance.
Anunay gave a pretty good analogy of how JWTs work at a high level as portable, trustable identifier, but since OAuth supports more than just JWT authentication it might warrant sharing a bit more detail.
Token introspection
In your question you rightly assumed that tokens need some way of being trusted, and that one such way would be to store the token in a private database and do a lookup whenever a token is presented to determine its validity. You would absolutely be able to instrument a valid OAuth server using a method like this by issuing the token using whatever form you wish and writing an introspection endpoint that performs the lookup. The OAuth spec is intentionally abstract so that the functional behavior of token introspection can take many forms.
One of the reasons for this level of abstraction is because while storing the tokens for direct lookup might be easy, it means that you have to store copies of these tokens in some form in a private database for comparison. This storage would in turn make you a honeypot for bad actors, both internally and externally, who would seek to impersonate your users en-masse. It's for this reason that many implementations of OAuth prefer to issue and validate tokens using public/private key encryption instead of direct lookups. This process is very much like the one Anunay described in his comment in that it issues tokens that are signed with a private key and verified with a public one. With this process, you no longer need to keep everyone's token in a private database, and instead simply need to secure private and public keys that are used to sign and verify tokens respectively.
JSON Web Tokens (JWTs) and reducing number of introspection calls
Anunay's response specifically referred to a common token structure that is generated using public/private key encryption and issued to users, JSON Web Tokens. These tokens are structured in such a way that they include the user information a backend service might need like the User ID, email address, and sometimes more, in a raw format that is directly readable to the backend API. In addition to this raw information however, JWTs include a duplicate copy of the data, but this duplicate copy is private-key encrypted. In order to trust a JWT token, all you have to do is use the public key and ensure that the private-key encoded payload is verifiable by applying the public key to the raw payload. Since public keys rarely change, many backend services cache the keys used for verification and elect not to do a token introspection on the issuing server since they already can verify the payload. This is how you'd optimize throughput on backend services that are protected via OAuth.
Since public keys can only be used to verify payloads and not produce them, these public keys are often broadcast by the servers that issued the tokens allowing anyone to "trust" the tokens it issues if they so choose. To learn more about this process, I'd recommend you research OpenID Connect.
Access token can be understood as an passport that government issue to the citizen based on proof of identity.
When you take it to another country, they look at the document and trust it because they trust the country and you because you are the holder of that document with you details.
They trust the fact that passport cannot be fiddled with and allow you entry
Now for access token, in very simple terms, authorization server verifies the user. Once verified it issues the user a JWT token (Access Token). This token is signed with private key. It has your details and is encoded along with signature. Now you can take this token to any third party who has got the public key and trust the authorization server. Now when you share the access token with this third party, it use public key to verify the token and check for expiry. If valid it allows you in.
So API doesn't really need to talk to auth server or keep any details about the token. All its needs is a public key to decode the token.
Now there are two important things. One if you ever let loose your access token, or some one who is not intended to get hold of your token gets it, he can do what ever he wants and auth server will not be able to do much. However as you see this approach reduces the chattiness of the systems specially microservices.
So to address this we limit the expiry of access token. Like passport, it comes with expiry. Shorter you keep it,user have to go and get the token refreshed with auth server. Every time he does so, auth server gets a change to verify creds and other details. If they do not match access token will not be refreshed.
I would like to seek help from you guys.
I have multiple RESTful API services running in NodeJS Express. Each API is hosted by different NodeJS with different port. And in our front-end, it is accessible via reverse proxy.
We are now moving to a secured services. However, there's a problem in authenticating with the services. The front-end should request 1 auth token upon login that can be used in accessing the internal API services (API is also accessible in our public domain /api/).
How can we solve this problem?
Current Setup
You could issue a signed JWT token upon login (see https://jwt.io/).
The front end application has to send the token back with each API call.
Each API server has to know in advance the key (public key or symmetric key depending on the type of the signature algorithm) and use the key to check the signature of the token is valid.
If it is valid, the API server knows it can trust the token content, and decide whether to serve the request. The token would contain the identity of the user, expiration time, ...
Note that signing the token does not encrypt the data: if you need to convey sensitive data through the token, it needs to also be encrypted
Thus it is not necessary to establish a session and then share the session across the many API instances. Knowing the key is enough to trust the token content
To pass the JWT in API calls you can use a header:
Authorization : Bearer theBase64EncodedToken
Of course, it is up to you to check if this scheme satisfies the security concerns related to your application.
I have some idea about OAuth token and used it in my last project. We used to store roles inside it so that resource server (WebAPI) does not have to request any more data to taken any decision on the authorization. Although authorization was based on permissions (that were mapped against roles). And resource server stored the mapping between role and permission.
In my current project, we are planning to use Azure Active directory. But in this project, we need to store one custom field and this field is the basis of all authorization model (along with roles). Although, in AAD (azure active directory), you can have custom fields but these fields cannot be sent in the form of claims.
So, my resource server will have to request this field for every user, once it receives the token from the client application. It can obviously store this in the cache for further request. But this does not look natural to me.
I believe, all the required for authorization should be part of OAuth token.
Please share your thoughts.
Not particulary for AAD , But if you want to keep everything in token then for sure You MUST encrypt the token. Considering that you are encrypting the token, There are three approaches that come to my mind:
Simple one, Authz Server encrypts the token with some private password. On arrival of token on Resource Server, it sends the token to Authz Server for validation and contents (Introspection API or OpenID Connect like API)
In next two approaches, Authz Server encrypts the token and RS decrypts the token locally.
When you register the Resource Server, Register it with public key of Resource Server (RS has Public and private key pair). Authz Server generates a random password to encrypt the token payload. Random password is ecrypted using the public key of Resource Server and added to JWT token header. Now when token reaches RS, it first decrypts the password using private key it has and then it uses that password (symmetric key encryption) to decrypt the payload. Everytime a new password needs to be generated to make sure that attacker sees new encrypted String everytime.
Similar approach as above, Here when Resource Server is registered (RS must be online) with public key of it, Authz Server contacts the RS and does SSL kind of handshake and they both exchange a long term session key which might actually last for 1 year or more (depending on security constrains of Your enterprise). Then when authz server generates the token, it encrypts it with session key and this time it doesn't add the session key to token header. Token goes to RS, RS check if it has a session key, if it has it tries to decrypt the payload using same session key. For error avoidance, RS can store the validity of Session key as well.
Azure AD doesn't support customizing the claims issued in the token.
However as a workaround, you can add the custom claims by querying Azure AD Graph in you project after the token is verified.
Here is a helpful article about Extending the Azure AD directory schema with custom properties.
I have a simple question about SSO flow with JWT
Let's say we have separate Authorization Server, which provides the JWT to the client app/server and Resource server, where client trying to access with that token.
The question is, should Resource server validate token by itself (e.g. share private certificate with Auth Server) or should it request Auth Server to validate JWT for each client request?
The JWT specification was built with scalability in mind. The purpose of JWT's design is that any trusted app can validate a the signature block. If you care about performance then use a SHA-256 HMAC and validate the signature locally on each endpoint with a shared secret. Using an asymmetric signature for JWT creates overhead, but you can store the public key on endpoints that verify but not issue JWT, and then the private key on the central authority that issues tokens. This separation of concern between validation and issuing reduces the possibilities that the token creation process can be subverted by an adversary (Read: Defense-in-depth).
If you need to revoke tokens in real time, then need a central authority which validates each token. This works, but it defeats the purpose of JWT's design, and the system would be better off just issuing a cryptogrpahic nonce as the token.