JSON Web Signature (JWS)
  • is a signed JSON Web Token (JWT)
  • the purpose of a signature is to allow one or more parties to establish the authenticity of the JWT. We use JWS to sign the session data which can be used to verify that the data has not been tampered with
  • this does not prevent other parties from reading the contents of the JWT (for encryption see JWE)

JWS - Signing Schemes

  • HMAC - it combines a certain payload with a shared-secret-key using a cryptographic hash function (e.g. SHA-256) and produces a signature that can be used to verify the message. This is a so-called shared-secret signing scheme since both the party that generates the signature and the party that verifies it knows the secret. And since both parties know it, both can generate a new signed message.
  • RSASSA - unlike HMAC, it allows the receiving parties to only verify the authenticity of a message, but not generate it. The algorithm is based on the private key scheme. The private key can be used to both create a signed message and verify its authenticity. The public key, in contrast, can only be used to verify the authenticity of a message. This is important in one-to-many signing scenarios, like Single-Sign-On, where there’s only one producer of the message and many consumers. If, for example, a legitimate consumer turns malicious, it is impossible for it to modify a message without the other parties noticing

JWS - Structure (Overview)

in its compact form, a JWS consists of 3 parts separated by dots (.):

  • header
  • payload
  • signature

a JWS typically looks like the following:

header.payload.signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

use jwt.io Debugger to decode, verify, and generate JWSs

JWS - Structure (Details)

The header typically consists of two parts: the type of the token, which is JWS, and the signing algorithm being used, such as HMAC-SHA256 or RSA.

example header (specifying HMAC-SHA256):

{  "alg": "HS256",    "typ": "JWT"}

the Header is compacted into a single line with no spaces

{"alg":"HS256","typ":"JWT"}

The Header is then Base64url Notation encoded to form the first part of the JWS:

base64UrlEncode('{"alg":"HS256","typ":"JWT"}') 

resulting:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

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: registeredpublic, and private claims.

example payload:

{   "sub": "1234567890",   "name": "John Doe",   "admin": true}

The Payload is compacted into a single line with no spaces:

{"sub":"1234567890","name":"John Doe","admin":true}

The Payload is then Base64url Notation encoded to form the second part of the JWS:

base64UrlEncode('{"sub":"1234567890","name":"John Doe","admin":true}')

resulting:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

To create the signature part you have to take the encoded header, the encoded payload, a secret, and the algorithm specified in the header, and sign that.

For example, if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:

HMACSHA256( base64UrlEncode(header) + "." +              base64UrlEncode(payload),             shared-secret-key )

The signature is used to verify the message wasn’t changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWS is who it says it is.

The Signature is then Base64url Notation encoded to form the third part of the JWS:

base64UrlEncode(signature)

resulting:

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

JWS - Structure (Putting It All Together)

the following shows the resulting JWS (i.e. 3 base64url strings delimited by a dot):

base64UrlEncode(header).base64UrlEncode(payload).base64UrlEncode(signature)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

use jwt.io Debugger to decode, verify, and generate JWSs