26 May 2019 - tsp
Last update 26 May 2019
5 mins
JSON web tokens are a standardized form of a token. An access token contains security credentials - for example for an login session or enabling a user to perform a single / multiple actions. It may contain information for the users, the devices or applications identity, the assigned groups or privileges, additional information like the allowed usage and normally should be kept secret like any other identifying information.
There are different token types. Some may only contain an identifier, others may also contain the granted access permissions (but of course not allowing the user to modify them). The first category that’s only containing an identifier and no additional information is called a bearer token. It can be best compared to a password and has to be verified by the targeted service - for example by comparing it against a session ID store or some other shared database. Of course this might be inpracticle due to scaling constraints (distributing millions of new tokens every second to all systems in a connected system of clusters worldwide is simply impossible, building a distributed store may not perform as well as one want’s to) or due to security constraints (it requires a single authority that verifies tokens or requires applications to have access to the token store).
JSON web tokens take another route. They contain identity information and optionally additional constraints (like the issuer, the audience, and expiration and validity time, an unique identifier) and optionally information required for authorization (users groups, resource IDs, embedded additional tokens for backend services, etc.). The service that verifies the tokens can use either a shared known secret - in this case an keyed-hash message authentication code (HMAC) is applied to the JSON data - or verify a signature against a known public key used by the token creating system (RSA signatures using RSASSA-PKCS1-v1_5 with SHA-256 hash or ECDSA using P-256 curve and the same hash algorithm).
Additionally tokens may also be encrypted (for example when they contain information that should not be known to the users).
The approach of using signed tokens has multiple advantages:
Of course using such tokens also has a drawback:
Normally the problem of missing logout functionality is solved by using two different types of tokens. Simple signed and expiring tokens that live only a short time (for example 6 hours) that can be used in a decentralized way and long living tokens that can be used to renew the short lived ones which will trigger a validation against a shared authentication database (i.e. using signed tokens for short lived tokens and bearer tokens as long lived ones).
Of course one has to keep in mind that tokens have to be transmitted on every access in case of a REST system (like HTTP applications) so their size somewhat matters. Also their storage in HTTP context will most likely be a cookie - since the size of a cookie is limited to 4 KByte on most browsers and a maximum of 50 cookies (one could chain multiple ones in many implementations - but there are some out there who limit to 4 KByte anyways) one should limit the size to approximately 4 KByte.
Basically the content of a JWT is just a JSON object containing all claims. An additional
header is built (that’s also a JSON structure) that contains algorithm and type information.
The Algorithms are typically HS256
(HMAC with SHA256) or RS256
(RSA signatures
with SHA-256). In theory the method none
would also be specifyable but of course
since that would allow modification of the tokens by the user which is just something one
doesn’t want to occure (since one wants to trust token content).
The Token itself consists of the base64 encoded header followed by a dot, the base64 encoded payload followed by a dot and the base64 encoded hash or signature.
For example the content
{
"iss":"Test RSA Issuer 3",
"iat":1558889251
}
could result in a token like the following (RS512 token using an 4096 bit RSA key) 780 byte token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJpc3MiOiJUZXN0IFJTQSBJc3N1ZXIgMyIsImlhdCI6MTU1ODg4OTA5Mn0.bNYUfzyo21dEL6F7t0dkCnjtfNvom5AdsOwUxxNKp9Qb9RqPGpAtfhSFKnDDEc97FxSTzD5uHFF96uHKymtGcj1BGY7GYuVETqNN2TVHYQtgJmAta-34UI90-n_qPLSFEN372vUCtUSj7sNNs-uZdBf5SZN7ACILvuqzzya9D3af4atcKCyxniC7BC3L7s9jhhD55fropKr86KPoouH4rjdAXOgCkLetzQbKWrAoLXlzWLJbEu2NCw5eAuwnBox6gmNahSF6RnVQ57pWC8q3oNj8FjW10TLURqLOJFtH22XdE91UZiaqgnqeDt6mu0gNwbrvqkDfdBrE4Kqprs2LHI80eOiNlAEvWEE_rGj06_yjE_M5-AGv7DqzxLjndnj9DhKkPXCh8v6haVaJ91QLvTwe84eIPPZrw87bVl1mqkU6SnOCWCjE2-9iH7FRQlAqd0OvYbicU3ohHsqPAZK9bx6oI6lDcXAWYBUuGE1iOcSvGpTa1Y45UYB3PT8faBmkwEhpD9XJKkXYVmXaeJABEYb_te31814rLfZ34hUhXM0Obqx-Sq_ZZGNXz74K0NrFcxUUiCCFHCS6vMteLgeCOiIW7iUwq7pc0DGnqe-KnLcX8iA5H3Miak9yd5IsuBuzCyzLoV-jdLcx2aD9w8sDR4T4lB7DZ7M38MWFCZw6mY0
iss
is the one who created the tokensub
identifies the user or application that is identified by this tokenaud
is (optionally) the entity that this token should be used against.
With this attribute one can restrict the usage of a token to a given backend.exp
and not-before nbf
can impose a constraint on the validity
of the tokeniat
issued-at token gives some information about the creation time of the token
and may be used during revocation processesjti
may be the wrapper around a traditional session ID - it uniquely identifies
the token. It may also be used during revocation process.There are many implementations out there. One can see an impressive list at jwt.io. I’ve also implemented a subset (only signed, not encrypted tokens) in PHP and Java.
This article is tagged:
Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)
This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/