-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ref component and jwt article (#7)
- Loading branch information
Showing
5 changed files
with
206 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
--- | ||
title: JSON Web Token (JWT) | ||
tags: [authentication, authorization, jwt] | ||
description: JSON Web Token (JWT) is an open standard defined in RFC 7519 that enables secure communication between two parties. It is compact, URL-safe, and self-contained, making it ideal for transmitting authentication and authorization data between services. | ||
--- | ||
|
||
## What is a JSON Web Token (JWT)? | ||
|
||
JSON Web Token (JWT) is widely used in modern web applications and open standards such as OpenID Connect, facilitating authentication and authorization. While the official [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) serves as an essential reference, it will be challenging for beginners to understand. In this article, we'll focus on the core concepts of JWT and present them in straightforward language with examples. | ||
|
||
## Why do we need JWT? | ||
|
||
Nowadays, it's pretty common to use JSON to exchange data between two parties. Consider a JSON object representing a user: | ||
|
||
```json | ||
{ | ||
"sub": "foo", | ||
"name": "John Doe" | ||
} | ||
``` | ||
|
||
> `sub` is short for "subject", which is a [standard claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) in OpenID Connect to represent the user identifier (user ID). | ||
How can we guarantee the **integrity** of this JSON object? In other words, how can we make sure that the data is not tampered with during the transmission? A common solution is to use digital signatures. For example, we can use [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography): the server signs the JSON object with its private key, and the client can verify the signature with the server's public key. | ||
|
||
In a nutshell, JWT offers a standardized approach to representing the JSON object and its signature. | ||
|
||
> JWT can also be used to encrypt the JSON object, but it's not the focus of this article. | ||
## The format of JWT | ||
|
||
Since there are many algorithms for creating digital signatures, it's necessary to specify the algorithm used for JWT signing. This is accomplished by constructing a JSON object: | ||
|
||
```json | ||
{ | ||
"alg": "HS256", | ||
"typ": "JWT" | ||
} | ||
``` | ||
|
||
> `alg` is short for "algorithm", and `typ` is short for "type". | ||
Typically, `typ` is set to `JWT` in uppercase. For our example, `alg` is `HS256`, which stands for [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) (we'll explain it soon), and indicates we're using this algorithm to create the signature. | ||
|
||
Now, we have all the ingredients for a JWT: | ||
|
||
- Header JSON: Algorithm and type | ||
- Payload JSON: The actual data | ||
- Signature: The signature encompassing the header and payload | ||
|
||
However, certain characters like spaces and line breaks are not friendly to network transmission. Therefore, the header and payload need to be **Base64URL-encoded**. The typical JWT looks like this: | ||
|
||
``` | ||
{{header}}.{{payload}}.{{signature}} | ||
``` | ||
|
||
> The `.` serves as the delimiter. | ||
Let's put everything together and create a JWT: | ||
|
||
### Header | ||
|
||
JSON: `{"alg":"HS256","typ":"JWT"}` | ||
|
||
Base64URL encoded: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9` | ||
|
||
### Payload | ||
|
||
JSON: `{"sub":"foo","name":"John Doe"}` | ||
|
||
Base64URL encoded: `eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ` | ||
|
||
### Signature | ||
|
||
In HMAC-SHA256, the signature is created with a secret: | ||
|
||
``` | ||
HMAC-SHA256(base64Url(header) + "." + base64Url(payload), secret) | ||
``` | ||
|
||
For instance, with the secret as `some-great-secret`, the signature becomes: `XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g`. | ||
|
||
### JWT | ||
|
||
The final JWT is: | ||
|
||
``` | ||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g | ||
``` | ||
|
||
This valid JWT can be verified by any party possessing the secret. | ||
|
||
## Choose the signing algorithm | ||
|
||
As mentioned earlier, there are various algorithms to create digital signatures. We used `HS256` as an example, but it may not be strong enough since the secret must be shared between the parties (e.g. the client and the server). | ||
|
||
In real-world scenarios, clients may include public applications like React apps that cannot keep the secret safe. Consequently, the preferred approach involves utilizing public-key cryptography (i.e. asymmetric cryptography) for signing the JWT. Let's start with the most popular algorithm: [RSA](https://en.wikipedia.org/wiki/RSA_cryptosystem). | ||
|
||
### RSA | ||
|
||
RSA, an asymmetric algorithm, uses a pair of keys: a public key and a private key. The public key is used to verify the signature, while the private key is used for signing. | ||
|
||
The header JSON for RSA looks like this: | ||
|
||
```json | ||
{ | ||
"alg": "RS256", | ||
"typ": "JWT" | ||
} | ||
``` | ||
|
||
> `RS256` stands for RSA-SHA256, which means the signature is created with the RSA algorithm and SHA256 hash function. You can also use `RS384` and `RS512` to create signatures with SHA384 and SHA512 hash functions, respectively. | ||
The signature is created with the private key: | ||
|
||
``` | ||
RSA-SHA256(base64Url(header) + "." + base64Url(payload), privateKey) | ||
``` | ||
|
||
Again, we can assemble these parts to create a JWT, and the final JWT looks like this: | ||
|
||
``` | ||
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.{{signature}} | ||
``` | ||
|
||
Now, the client can verify the signature without knowing the private key. | ||
|
||
### ECDSA | ||
|
||
Although RSA is widely adopted, it suffers from larger signature sizes, sometimes surpassing the combined size of the header and payload. The Elliptic Curve Digital Signature Algorithm (ECDSA) is another asymmetric algorithm that can create more compact signatures and is more performant. | ||
|
||
To generate a private key for ECDSA, we need to choose a curve. This is out of the scope of this article, but you can find more information [here](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography#Elliptic_Curve_Digital_Signature_Algorithm). | ||
|
||
The header JSON for ECDSA looks like this: | ||
|
||
```json | ||
{ | ||
"alg": "ES256", | ||
"typ": "JWT" | ||
} | ||
``` | ||
|
||
> `ES256` stands for ECDSA-SHA256, which means the signature is created with the ECDSA algorithm and SHA256 hash function. You can also use `ES384` and `ES512` to create signatures with SHA384 and SHA512 hash functions, respectively. | ||
The signature is created with the private key: | ||
|
||
``` | ||
ECDSA-SHA256(base64Url(header) + "." + base64Url(payload), privateKey) | ||
``` | ||
|
||
The final JWT retains the same structure as RSA but with a significantly shorter signature: | ||
|
||
``` | ||
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.{{signature}} | ||
``` | ||
|
||
## Verify the JWT | ||
|
||
Verifying a JWT is straightforward as the reverse process of creating a JWT: | ||
|
||
1. Split the JWT into three parts (header, payload, and signature) using the `.` delimiter. | ||
2. Decode the header and payload with Base64URL. | ||
3. Verify the signature with the algorithm specified in the header and the public key (for asymmetric algorithms). | ||
|
||
There are many libraries that are available to assist with JWT verification, such as [jose](https://github.com/panva/jose) for Node.js and web browsers. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
import { articles } from "../libraries/articles"; | ||
type Props = { | ||
/** | ||
* The internal slug of the reference. It must be a valid slug of an article loaded in the site. | ||
* @see {@link articles} for the list of available articles. | ||
*/ | ||
slug: string; | ||
}; | ||
const { slug } = Astro.props; | ||
const found = articles.find((article) => article.slug === slug); | ||
if (!found) { | ||
throw new Error(`The article with slug "${slug}" was not found.`); | ||
} | ||
--- | ||
|
||
<svg viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path | ||
d="M7.49992 8.56466H8.33325C8.55427 8.56466 8.76623 8.47686 8.92251 8.32058C9.07879 8.1643 9.16658 7.95234 9.16658 7.73133C9.16658 7.51031 9.07879 7.29835 8.92251 7.14207C8.76623 6.98579 8.55427 6.89799 8.33325 6.89799H7.49992C7.2789 6.89799 7.06694 6.98579 6.91066 7.14207C6.75438 7.29835 6.66659 7.51031 6.66659 7.73133C6.66659 7.95234 6.75438 8.1643 6.91066 8.32058C7.06694 8.47686 7.2789 8.56466 7.49992 8.56466ZM7.49992 10.2313C7.2789 10.2313 7.06694 10.3191 6.91066 10.4754C6.75438 10.6317 6.66659 10.8436 6.66659 11.0647C6.66659 11.2857 6.75438 11.4976 6.91066 11.6539C7.06694 11.8102 7.2789 11.898 7.49992 11.898H12.4999C12.7209 11.898 12.9329 11.8102 13.0892 11.6539C13.2455 11.4976 13.3333 11.2857 13.3333 11.0647C13.3333 10.8436 13.2455 10.6317 13.0892 10.4754C12.9329 10.3191 12.7209 10.2313 12.4999 10.2313H7.49992ZM16.6666 7.68133C16.6579 7.60477 16.6411 7.52935 16.6166 7.45633V7.38133C16.5765 7.29564 16.5231 7.21688 16.4583 7.148L11.4583 2.14799C11.3894 2.08318 11.3106 2.02973 11.2249 1.98966C11.2 1.98613 11.1748 1.98613 11.1499 1.98966C11.0653 1.94111 10.9718 1.90995 10.8749 1.89799H5.83325C5.17021 1.89799 4.53433 2.16139 4.06549 2.63023C3.59664 3.09907 3.33325 3.73495 3.33325 4.39799V16.0647C3.33325 16.7277 3.59664 17.3636 4.06549 17.8324C4.53433 18.3013 5.17021 18.5647 5.83325 18.5647H14.1666C14.8296 18.5647 15.4655 18.3013 15.9344 17.8324C16.4032 17.3636 16.6666 16.7277 16.6666 16.0647V7.73133C16.6666 7.73133 16.6666 7.73133 16.6666 7.68133ZM11.6666 4.73966L13.8249 6.89799H12.4999C12.2789 6.89799 12.0669 6.8102 11.9107 6.65392C11.7544 6.49764 11.6666 6.28568 11.6666 6.06466V4.73966ZM14.9999 16.0647C14.9999 16.2857 14.9121 16.4976 14.7558 16.6539C14.5996 16.8102 14.3876 16.898 14.1666 16.898H5.83325C5.61224 16.898 5.40028 16.8102 5.244 16.6539C5.08772 16.4976 4.99992 16.2857 4.99992 16.0647V4.39799C4.99992 4.17698 5.08772 3.96502 5.244 3.80874C5.40028 3.65246 5.61224 3.56466 5.83325 3.56466H9.99992V6.06466C9.99992 6.7277 10.2633 7.36359 10.7322 7.83243C11.201 8.30127 11.8369 8.56466 12.4999 8.56466H14.9999V16.0647ZM12.4999 13.5647H7.49992C7.2789 13.5647 7.06694 13.6525 6.91066 13.8087C6.75438 13.965 6.66659 14.177 6.66659 14.398C6.66659 14.619 6.75438 14.831 6.91066 14.9873C7.06694 15.1435 7.2789 15.2313 7.49992 15.2313H12.4999C12.7209 15.2313 12.9329 15.1435 13.0892 14.9873C13.2455 14.831 13.3333 14.619 13.3333 14.398C13.3333 14.177 13.2455 13.965 13.0892 13.8087C12.9329 13.6525 12.7209 13.5647 12.4999 13.5647Z" | ||
></path> | ||
</svg> | ||
<a href={`/${slug}`}>{found.frontmatter.title}</a> | ||
<style> | ||
svg { | ||
vertical-align: sub; | ||
height: 1.1em; | ||
fill: rgb(158, 120, 255); | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters