JWT - ghdrako/doc_snipets GitHub Wiki
debuger https://jwt.io/
JSON Web Token (JWT) defines a container to transport data between interested parties.There are multiple applications of JWT. The OpenID Connect is one of them. In OpenID Connect the id_token is represented as a JWT. Both in securing APIs and Microservices, the JWT is used as a way to propagate and verify end-user identity.
jwt-decode() {
jq -R 'split(".") |.[0:2] | map(@base64d) | map(fromjson)' <<< $1
}
% jwt-decode eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
[
{
"alg": "HS256",
"typ": "JWT"
},
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
]
A signed JWT is known as a JWS (JSON Web Signature). In fact a JWT does not exist itself — either it has to be a
- JWS (JSON Web Signature) or a
- JWE (JSON Web Encryption).
Its like an abstract class — the JWS and JWE are the concrete implementations. https://medium.facilelogin.com/jwt-jws-and-jwe-for-not-so-dummies-b63310d201a3
The JSON Web Signature (JWS) is the most commonly used format of a JWT, which has three parts with a dot (.) separating each part.
- The first part is known as the JSON Object Signing and Encryption (JOSE) header.
- The second part is the claim set or the body (or payload).
- The third part is the signature.
JWTs consist of the following three parts:
-
Header
— Composed of the type and the hashing algorithm -
Payload
— Contains the user claims -
Signature
— Used to verify the authenticity of the JWT
Those three parts—the header, payload, and signature—are separated by dots (.) and Base64 URL encoded, which makes a JWT perfect for use in HTTP requests.
JWT typically looks like the following.
xxxxx.yyyyy.zzzzz
The JOSE header expresses the metadata related to the token, such as an algorithm used to sign the message.
The alg
header identifies the JWS or JWE cryptographic algorithm that was used to
authenticate or encrypt the contents. This is also the only mandatory header value.
{
"alg": "HS256", # or "RS256"
"typ": "JWT"
}
This JSON is Base64Url encoded to form the first part of the JWT
The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.
- Registered claims: These are a set of predefined claims which are not mandatory but recommended, to provide a set of useful, interoperable claims. Some of them are: iss (issuer), exp (expiration time), sub (subject), aud (audience), and others.
- Public claims: These can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.
- Private claims: These are the custom claims created to share information between parties that agree on using them and are neither registered or public claims.
Example Registered claims
{
"exp": 4743986578, # Expiration time
"group": "user", # "group" claim
"iat": 1590386578, # Issue time
"iss": "[email protected]", # Token issuer
"sub": "9b792b56-7dfa-4e4b-a83f-e20679115d79" # Subject or principal of the token
}
The claims enable the service to determine the identity and authorization of a client.
The value of the exp
attribute in the decoded JWT claim set
(shown in figure H.3) expresses the time of expiration in seconds, which is calculated from
1970-01-01T0:0:0Z as measured in Universal Time Coordinated (UTC). Any recipient of a JWT
must make sure that the time represented by the exp attribute is not in the past when
accepting a JWT.
The iat
attribute in the JWT claim set expresses the time when the JWT was
issued. That too is expressed in seconds and calculated from 1970-01-01T0:0:0Z as measured
in UTC.
The nbf
(not before) attribute - You shouldn’t start processing a JWT (or accept it
as a valid token) before the time specified in a nbf attribute. The value of nbf is also
expressed in seconds and calculated from 1970-01-01T0:0:0Z as measured in UTC.
The iss
attribute ID is set to the value sts.ecomm.com in the decoded JWT claim set, which is
the issuer of the JWT. The JWT is signed by the issuer’s private key. In a typical microservices
deployment within a given trust domain, all the microservices trust a single issuer. The issuer
is also called a security token service (STS).
The aud
attribute specifies the audience of the token—in other words, the intended recipient of the token.
The value of the aud attribute can be any
string or an URI that’s known to the microservice or the recipient of the JWT. Each microservice
must check the value of the aud parameter to see whether it’s known before accepting any
JWT as valid. If you’ve a microservice called foo with the audience value foo.ecomm.com, the
microservice should reject any JWT carrying the aud value bar.ecomm.com
, for example. The
logic in accepting or rejecting a JWT based on audience is up to the corresponding microservice
and to the overall microservices security design. By design, you can agree that any
microservice will accept a token with the audience value <microservice identifier>.ecomm.com
or *.ecomm.com
, for example.
Claim | Name | Purpose |
---|---|---|
iss | Issuer | Indicates who created the JWT. This is a single string and often the URI of the authentication service. |
aud | Audience | Indicates who the JWT is for. An array of strings identifying the intended recipients of the JWT. If there is only a single value, then it can be a simple string value rather than an array. The recipient of a JWT must check that its identifier appears in the audience; otherwise, it should reject the JWT. Typically, this is a set of URIs for APIs where the token can be used. |
iat | Issued-At | The UNIX time at which the JWT was created. |
nbf | Not-Before | The JWT should be rejected if used before this time. |
exp | Expiry | The UNIX time at which the JWT expires and should be rejected by recipients. |
sub | Subject | The identity of the subject of the JWT. A string. Usually a username or other unique identifier. |
jti | JWT ID | A unique ID for the JWT, which can be used to detect replay. |
Only the issuer, issued-at, and subject claims express a positive state- ment. The remaining fields all describe constraints on how the token can be used rather than making a claim. These constraints are intended to prevent certain kinds of attacks against security tokens, such as replay attacks in which a token sent by a genu- ine party to a service to gain access is captured by an attacker and later replayed so that the attacker can gain access. Setting a short expiry time can reduce the window of opportunity for such attacks, but not eliminate them. The JWT ID can be used to add a unique value to a JWT, which the recipient can then remember until the token expires to prevent the same token being replayed. Replay attacks are largely pre- vented by the use of TLS but can be important if you have to send a token over an insecure channel or as part of an authentication protocol.
The issuer and audience claims can be used to prevent a different form of replay attack, in which the captured token is replayed against a different API than the origi- nally intended recipient. If the attacker replays the token back to the original issuer, this is known as a reflection attack, and can be used to defeat some kinds of authentica- tion protocols if the recipient can be tricked into accepting their own authentication messages. By verifying that your API server is in the audience list, and that the token was issued by a trusted party, these attacks can be defeated.
The payload is then Base64Url encoded to form the second part of the JSON Web Token.
A JWS can be serialized in two formats or represented in two ways:
- compact serialization
- JSON serialization.
To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
signature = Crypto(secret, base64(header), base64(payload))
To use the HMAC SHA256 algorithm, the signature will be created in the following way:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
The JWT is issued by an authentication server that contains a private key for signing the token and a public key for validating it. The public key is known as a JSON Web Key Set (JWKS) and is exposed at a well-known HTTP endpoint.
There are multiple solutions to set up an authentication server:
- It can be implemented in the application backend framework.
- It can be implemented as a service on its own, such as OpenIAM (openiam.com) or Keycloak (keycloak.org).
- It can be implemented as an Identity-as-a-Service solution, such as Auth0 (auth0.com), Okta (okta.com), and so on.
Step to using JWT:
- The client gets the JWT by authenticating to the authentication server.
- The client using JWT in HTTP Request to Server - Whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:
Authorization: Bearer <token>
- The server gets the JSON Web Key Set (JWKS) to validate the token sent by the client. The JWKS contains the public key that is used to decrypt the signature which is then compared to the hash of the token data. If those match, the token claims can be trusted.
Property in the key is defined by the JWK specification RFC 7517 Section 4 or, for algorithm-specific properties, in RFC 7518].
Property name | Description |
---|---|
alg | The specific cryptographic algorithm used with the key. |
kty | The family of cryptographic algorithms used with the key. |
use | How the key was meant to be used; sig represents the signature. |
x5c | The x.509 certificate chain. The first entry in the array is the certificate to use for token verification; the other certificates can be used to verify this first certificate. |
n | The modulus for the RSA public key. |
e | The exponent for the RSA public key. |
kid | The unique identifier for the key. |
x5t | The thumbprint of the x.509 cert (SHA-1 thumbprint). |
JWS - a signed representation of the JWT a signed JWT (i.e. JWS) has base64 encoded header, payload, and signature separated by dot (.) . Since the signature is created by using the private key, its validation requires access to the corresponding public key.
A JSON Web Key (JWK) is a JSON data structure that represents a cryptographic key. A JWK Set JSON data structure as the name suggests, represents a set of JWKs.
JWK will have members that are key type specific , the idea being that it provides enough information to the consumer to verify signature.
The “x5c” (X.509 certificate chain) Header Parameter contains the X.509 public key certificate or certificate chain corresponding to the key used to digitally sign the JWS (JSON Web Signature).
x5c means x509 certificate chain, represented as an array of certificates. The first certificate in the array is the one that contains the public key represented by this JWK.
- Reads the x5c[0] member and parses it into a Certificate
- Reads the public key from that cert
- Creates a public key from the modulus (member n) and exponent (member e) of the JWK
- Compares that the two keys are indeed the same
While JWT itself is just one specification (https://tools.ietf.org/html/rfc7519), it builds on a collection of standards collectively known as JSON Object Signing and Encryption (JOSE). JOSE itself consists of several related standards:
-
JSON Web Signing (JWS, https://tools.ietf.org/html/rfc7515) defines how JSON objects can be authenticated with HMAC and digital signatures.
-
JSON Web Encryption (JWE, https://tools.ietf.org/html/rfc7516) defines how to encrypt JSON objects.
-
JSON Web Key (JWK, https://tools.ietf.org/html/rfc7517) describes a standard format for cryptographic keys and related metadata in JSON.
-
JSON Web Algorithms (JWA, https://tools.ietf.org/html/rfc7518) then specifies signing and encryption algorithms to be used. JOSE has been extended over the years by new specifications to add new algorithms and options. It is common to use JWT to refer to the whole collection of specifica- tions, although there are uses of JOSE beyond JWTs.
-
JWT – JSON Web Token – The resulting signed Identity Assertion – RFC 7519
-
JWA – JSON Web Algorithm – A set of supported algorithms for signing a JWT – RFC 7518
-
JWS – JSON Web Signature – Officially a superset to describe JSON data structures secured with digital signatures, but the relevant part is that the spec defines the how to describe the process used for signing – RFC 7515
-
JWK – JSON Web Key – A mechanism for representing keys for validating JWTs – RFC 7517
JSON Web Token (JWT) is a means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS) and/or encrypted using JSON Web Encryption (JWE).
A JSON Web Key provides a mechanism for distributing the public keys that can be used to verify JWTs. As a result, identity providers will typically provide an API endpoint to allow clients to retrieve a JWK, which they can then use to verify tokens issued by that identity provider.
Typically, as it relates to JWT verification, a JWK will look like this (though technically this is a JWK Set, containing a single JWK entry):
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"x5t": "M2maFm3VYlMBOn3GetVWGXkrKrk",
"kid": "SIGNING_KEY",
"x5c": [
"MIIE………(base64 encoded cert)………..zM=",
"MIIC………(base64 encoded cert)………..tow=="
],
"alg": "RS256"
}
]
}
{
"keys": [
{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"x5c": [ "..."
],
"n": "...",
"e": "AQAB",
"kid": "NjVBRjY5MDlCMUIwNzU4RTA2QzZFMDQ4QzQ2MDAyQjVDNjk1RTM2Qg",
"x5t": "NjVBRjY5MDlCMUIwNzU4RTA2QzZFMDQ4QzQ2MDAyQjVDNjk1RTM2Qg"
}
]}
JWKs were intended to allow clients to select an appropriate key for whatever JWTs are presented to them, and so most of these attributes are used to describe how to select the appropriate key.
https://redthunder.blog/2017/06/08/jwts-jwks-kids-x5ts-oh-my/
Upon initial authentication, the user will receive two tokens (note that the names might differ per auth provider):
- Access Token: Your typical JSON Web Token that is sent with every request. Contains the user claim.
- Refresh Token: This special kind of token is persisted in a database, mostly owned by an Authentication Service of some sort. This is often not a JWT — but rather a unique hash.
Access Token will be sent with every request (fetch blog posts, create blog post, add comment etcetera) and at some point the token will expired. Then, the front-end will send a refresh request with the refresh token. The auth server will generate a new Access Token (JWT) with the most up-to-date claims, and send it back to the user. The user will use this token until it’s expired, and then refresh again. Over and over.
Refresh tokens can be valid for months, and that is often the case. When the refresh token expires, the user will be signed out and need to authenticate again.
JWE represents an encrypted message using compact serialization or JSON serialization. A JWE is called a JWT only when compact serialization is used. In other words, a JWT can be either a JWS or a JWE, which is compact serialized and used to carry different types of assertions from one place to another. JWS addresses the integrity and no repudiation aspects of the data contained in it, while JWE protects the data for confidentiality. A compact-serialized JWE has five parts; the parts are base64url-encodedand separated by dots (.).
- A JOSE header is the part of the JWE that carries metadata related to the encryption.
- The JWE encrypted key,
- initialization vector, and
- ciphertext and
- authentication tag are related to the cryptographic operations performed during the encryption.