Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "How Clerk works" and "Client handshake" to initial concepts section #577

Draft
wants to merge 45 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
46ad0c1
moving how clerk works to concepts section
rachelnabors Dec 19, 2023
11baccf
Merge branch 'main' into clerk-concepts
rachelnabors Dec 19, 2023
b4387ff
fix lank
rachelnabors Dec 19, 2023
69e2627
remove slack and notion references under piggybacking
rachelnabors Dec 19, 2023
333c047
updating interstitial with handshake
rachelnabors Dec 20, 2023
46c931b
adding more about client handshake
rachelnabors Dec 20, 2023
680799c
Update docs/concepts/how-clerk-works.mdx
rachelnabors Dec 20, 2023
80ec970
incorporating Sok's feedback
rachelnabors Dec 22, 2023
80c8a9a
Merge branch 'main' into clerk-concepts
rachelnabors Dec 22, 2023
6009e4d
fix manifest
rachelnabors Dec 22, 2023
158443c
Update docs/concepts/client-handshake.mdx
rachelnabors Dec 22, 2023
0d91e7c
Update docs/concepts/client-handshake.mdx
rachelnabors Dec 22, 2023
876c4cf
Removing references to endpoint
rachelnabors Dec 22, 2023
e0aeb3e
remove information about the backend auth req
rachelnabors Dec 22, 2023
3c1a09f
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
1bdf9e4
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
03f8017
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
e502c73
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
3cf1f09
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
64be328
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
2e5ebe8
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
72b5695
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
ccd217a
Update docs/concepts/client-handshake.mdx
alexisintech Dec 22, 2023
b41d973
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
45e9149
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
22c0607
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
1683015
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
fd40e0a
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
71805a3
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
7bb4e38
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
1e6b0d7
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
e808d32
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
cac8bf9
Update docs/concepts/how-clerk-works.mdx
alexisintech Dec 22, 2023
2cd290e
Update docs/manifest.json
alexisintech Dec 22, 2023
5b82fd5
update sidenav icon; add meta desc for how clerk works
alexisintech Dec 22, 2023
4cdcdb2
add jwks link
alexisintech Jan 8, 2024
acddf44
add fapi ref link for /client/handshake endpoint
alexisintech Jan 8, 2024
067f5bf
remove braceketed phrases
alexisintech Jan 9, 2024
fe3d1bd
Update docs/concepts/client-handshake.mdx
alexisintech Jan 16, 2024
853a260
apply code review suggestions
alexisintech Jan 16, 2024
9963368
numbered points should be bullet points; update heading for clarity
alexisintech Feb 2, 2024
2106eae
Update docs/concepts/client-handshake.mdx
alexisintech Feb 5, 2024
086a917
add section that explains __client_uat cookie
alexisintech Feb 5, 2024
b349829
add example of handshake payload
alexisintech Feb 5, 2024
4f9c0b1
grammatical updates
alexisintech Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions docs/concepts/client-handshake.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Client handshake
description: The Client Handshake is a mechanism that is used to resolve a request’s authentication state from “unknown” to definitively signed in or signed out.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
type: conceptual
---

# The client handshake
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

Clerk uses a client handshake mechanism to resolve a request’s authentication state from unknown (`handshake`) to `signed-in` or `signed-out`. Clerk’s session management architecture relies on a short-lived session JWT to validate requests, along with a long-lived session that is used to keep the the session JWT fresh by interacting with the Frontend API. The long-lived session token is stored in an HttpOnly cookie associated with the Frontend API domain. If a short-lived session JWT is expired on a request to an application’s backend, the SDK doesn’t know if the session has ended, or if a new short-lived JWT needs to be issued. When an SDK gets into this state, it triggers the handshake.
rachelnabors marked this conversation as resolved.
Show resolved Hide resolved

With the handshake, we can resolve authentication state on the backend and ensure the request is properly handled as signed in or out, instead of being in a potentially “unknown” state. The handshake flow relies on redirects to exchange session information between FAPI and the application, ensuring the resolution of unknown authentication states minimizes performance impact and behaves consistently across different framework and language implementations.
rachelnabors marked this conversation as resolved.
Show resolved Hide resolved

## Handshake flow

The handshake mechanism operates by way of a redirect from the host application to a FAPI endpoint:

1. Request is made to an application using Clerk
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
2. Clerk SDK determines the authentication state of the request (`signed-in`, `signed-out`, or `handshake`).
3. If authentication state is `handshake`, Clerk responds with a 307 redirect to the handshake endpoint: `fapi/v1/client/handshake`
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
4. The handshake endpoint gets information about the current session and returns a handshake payload. The encoded handshake payload contains a list of `Set-Cookie` header directives to be passed along with the final response
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
1. If the session is active, a fresh session JWT cookie is returned
2. If the session is inactive, the session JWT cookie is wiped and the request will be treated as signed out
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
5. The handshake endpoint redirects back to the host application along with the handshake payload, encoded either in the URL (development) or as a cookie (production)
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
6. The handshake payload is parsed and `Set-Cookie` headers are set on the response
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
7. If an updated session JWT is returned, the JWT is verified
1. If successful, the request is treated as signed in
8. If an updated session JWT is not returned, the request is treated as signed out
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

## Scenarios that trigger a handshake

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A link to the basic concepts page when available in the section will be helpful as it explains the Clerk internals and the cookies.

<Callout type="warning">
A handshake is only triggered If a request is determined to be a document request (detected by the presence of the `Sec-Fetch-Dest: document` header, or `Accept: text/html`). Otherwise, the request is treated as `signed-out`.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
</Callout>

1. Development instance and a dev browser is detected in URL **[URL-based session sync]**
2. Production instance and request is being made to a satellite application **[satellite needs sync]**
3. Has a session token (`__session`), but no active client is detected (`__client_uat` = 0 or missing) **[session token without client UAT]**
4. Has active client (`__client_uat` > 0) but no session token **[client UAT without session token]**
5. Client UAT is more recent than current session token issued at (`__client_uat` > `sessionToken.iat`) **[session token outdated]**
6. Session token exists but is expired **[session token expired]**
7. Session token exists but is not active yet **[session token not active yet]**

## Handshake architecture

The handshake flow is composed of two main pieces:

1. The FAPI [`/client/handshake` endpoint](https://github.com/clerk/clerk_go/blob/main/api/fapi/v1/router/router.go#L223)
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
2. The [`@clerk/backend` `authenticateRequest()` method](https://github.com/clerk/javascript/blob/main/packages/backend/src/tokens/request.ts#L74)
rachelnabors marked this conversation as resolved.
Show resolved Hide resolved

### `/client/handshake` endpoint
rachelnabors marked this conversation as resolved.
Show resolved Hide resolved

The endpoint should always result in a redirect back to the provided `redirect_url`. Along with the response, a **[handshake payload](#handshake-payload)** is returned. The handshake endpoint also handles multi-domain syncing between a satellite and a primary domain. If possible, the handshake will return a refreshed session token, as well as updated dev browser (`__clerk_db_jwt`) and Client UAT (`__client_uat`) cookies.

### `@clerk/backend` method
rachelnabors marked this conversation as resolved.
Show resolved Hide resolved

The `authenticateRequest()` method from the backend package primarily handles determining the authentication state of a given `Request` object. If the request state is determined to be `handshake`, the method returns returns headers to redirect to the handshake endpoint. These headers must then be set on the response returned by the SDK.

On redirect back to an application from the handshake endpoint, `authenticateRequest()` will run again and parse the handshake payload. Based on the contents of the payload, the request is determined to definitively be `signed-in` or `signed-out` and handled accordingly. The cookie directives from the handshake payload are set as `Set-Cookie` headers on the final response.

### Handshake payload

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BRKalow Please add an example of a Handshake payload.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexisintech Please add the following example of the handshake payload:

  "handshake": [
    "__client_uat=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT",
    "__clerk_handshake=; Path=/; Domain=example.com; Expires=Thu, 01 Jan 1970 00:00:00 GMT",
    "__client_uat=1706822359; Path=/; Domain=example.com; Max-Age=315360000; Secure; SameSite=Lax",
    "__session=<...CLERK_SESSION_JWT...>; Path=/; Expires=Wed, 05 Feb 2025 09:08:53 GMT; Secure"
  ]
}```

The handshake payload is a signed JWT that contains an array of `set-cookie` header directives. This allows us to transfer cookies from the FAPI domain to the application’s domain across environments without additional cookie setting logic embedded into our SDKs. In development, the payload is transported in the URL in a `__clerk_handshake` query parameter. In production, the payload is transported in a `__clerk_handshake` cookie. On returning from the handshake endpoint, the handshake payload is parsed and the cookie directives are set on the final response.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
106 changes: 106 additions & 0 deletions docs/concepts/how-clerk-works.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: How Clerk works
description:
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
type: conceptual
---

# How Clerk works
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

## Development and production instances

Clerk provices both development and production environments for your app. Production instances are used for production, pre-production, or staging environments with fixed domains. Production instances offer the strongest security and performance guarantees. Development instances contain certain trade-offs meant to support ease of active development.

<Callout type="warning">
Never use a development instance in a production environment. Development instances don’t have strong security guarantees.
</Callout>

## Main objects

Clerk uses five main objects:

### [Client](/docs/references/javascript/client#client)

A client represents the current device or software accessing an application such as your web browser, native application for Android or iOS, Chrome Extension, or Electron app.

### [Session](/docs/references/javascript/session)

A session is a secure representation of the authentication state of the current user. Each client can hold multiple sessions on the same device. This is identical to how Gmail works in a browser.

### [User](/docs/users/overview)

A user represents the current user of the session. The object holds all the basic user information e.g. name, email addresses, phone numbers, etc… including their public, private, and unsafe metadata.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

### [Organization](/docs/organizations/roles-permissions)

An organization represents the current organization of the session. Users can belong to many organizations. One of them will be the current organization of the session.

### [Roles](/docs/organizations/roles-permissions)

A user belongs to an organization with a role that defines their permissions. Currently, Clerk supports two roles, `org:admin` and `org:member`.

## Clerk Frontend API (FAPI)

Every Clerk development and production instance has a dedicated [Frontend API](https://clerk.com/docs/reference/frontend-api). This is the authentication, session, user & organization management API you or your users will interact with within the web browser, native application, Chrome extension, or Electron app.

Clerk assigns a unique random API URL such as `https://delicate-wahoo-73.accounts.dev/sign-in` to each development instance. For production instances, the Frontend API lives at `https://clerk.[your-domain.com]`.

### How it works
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

Clerk's Frontend API is responsible for maintaining the authentication state of the current client (browser or native application). Based on the authentication's state (`signed-in`, `signed-out`, `handshake`) it mints a short-lived session [JSON Web Token (JWT)](/docs/backend-requests/making/jwt-templates) for the current user and session to be used by the host application that is secured by Clerk. The session JWT is stored in a cookie or can be retrieved at any time via the [`getToken()`](/docs/references/javascript/session#get-token) method.

### Clerk cookies

Clerk’s Frontend API uses two cookies for session management in production instances:

* `__client` cookie: a long-lived session that is used to keep the the session JWT fresh by interacting with the Frontend API.
* `__session` cookie: a short-lived session JWT to validate requests on your application or your API.

#### The `__client` cookie

This cookie is set on Clerk Frontend API (for example `https://clerk.<example.com>`) for each instance. It’s HTTP-only, first-party, and secure. It contains a long-lived client JWT that lasts 7 days by default. The duration is configurable in the Clerk Dashboard's [Sessions page](https://dashboard.clerk.com/last-active?path=sessions). The JWT identifies the current client (browser, native application, or chrome extension) and sets the current active sessions.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

#### The `__session` cookie

This cookie is set on the host application that is secured by Clerk (for example `https://dashboard.<example.com>`). It’s a JS cookie, it’s secure, and contains a short-lived session JWT that lasts 60 seconds. This JWT contains the current session, user, and organization identifiers and must be sent to the application API to authenticate API requests. In SSR, the `__session` cookie travels automatically to the server. ClerkJS ensures that the `__session` cookie is automatically refreshed in Client Side Rendering (CSR) and Server Side Rendering (SSR), ensuring a fresh session is always available.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

However, if a `__session` cookie is expired on a request to an application’s backend, the SDK doesn’t know if the session has ended, or if a new short-lived JWT needs to be issued. When an SDK gets into this state, it triggers Clerk's client handshake.

alexisintech marked this conversation as resolved.
Show resolved Hide resolved
### The client handshake

Clerk uses a client handshake mechanism to resolve a request’s authentication state from unknown (`handshake`) to `signed-in` or `signed-out`.

With this handshake, Clerk can resolve authentication state on the backend and ensure the request is properly handled as signed in or out, instead of being in a potentially unknown state. The handshake flow relies on redirects to exchange session information between FAPI and the application, ensuring the resolution of unknown authentication states minimizes performance impact and behaves consistently across different framework and language implementations.

Learn more about [how Clerk's client handshake works in this deep dive](/docs/concepts/client-handshake).
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

### Client piggybacking

Every Frontend API request except from `/v1/client/sessions/:id/tokens` that refreshes the Clerk session tokens, returns a response payload that contains two top level keys
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

```json
{
client: ...,
response: ...
}
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
```

The `response` key contains the resource or resources of each endpoint. The `client` key contains the client piggybacking payload. The client object identifies the current device and contains all sessions, users and organization data for the current device (see [Main Objects](#main-objects) section).
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

This is effectively the necessary frontend state for ClerkJS and powers the JS SDKs, the React hooks and the Components. It is a best-effort way for the backend to update the frontend state on every Frontend API request.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

It's not recommended to use Client piggybacking because of the following issues:

1. It’s a very large chunk of a tree-like state and doesn’t change often.
1. It’s hard to compute on the backend as it requires a lot of data from the database. The computation takes place on every request adding a significant overhead.
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
1. It’s best effort.
1. It’s not a two-way communication channel.

### Clerk Frontend API for non-standard web browsers
alexisintech marked this conversation as resolved.
Show resolved Hide resolved

Clerk offers a seamless authentication solution for non-standard web browser environments such as React Native applications, Chrome Extensions, and hybrid apps in platforms like Capacitor.js or Electron.

These platforms treat cookies differently than web browsers. As a result, ClerkJS should use the HTTP Authorization header instead of the `__client` cookie for secure communication with the Clerk Frontend API. To achieve session persistence, the `__client` JWT should be stored in a secure storage provided by each platform and then it should be injected into every Clerk Frontend API request.

## Clerk Backend API (BAPI)

Clerk's [Backend API](https://clerk.com/docs/reference/backend-api) is a restful CRUD API for the server side. It allows a sudo-level management of all Clerk objects.
11 changes: 11 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
["Fastify", "/quickstarts/fastify"]
]
],
[
{
"title": "Concepts",
"icon": "lightning-bolt",
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
"root": "concepts"
},
[
["How Clerk Works", "/concepts/how-clerk-works"],
["Client Handshake", "/concepts/client-handshake"]
alexisintech marked this conversation as resolved.
Show resolved Hide resolved
]
],
[
{
"title": "Guides",
Expand Down