From 8aadda9904e6178a47b1a79adefdd1b2bb96ad18 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 19 Nov 2024 19:30:20 -0800 Subject: [PATCH] adding docs pages --- docs/backend-requests/handling/manual-jwt.mdx | 55 +++++++++++-- docs/backend-requests/making/machine.mdx | 45 +++++++++++ docs/backend-requests/overview.mdx | 17 ++-- .../resources/machine-tokens.mdx | 81 +++++++++++++++++++ docs/manifest.json | 8 ++ .../backend/authenticate-request.mdx | 35 ++++++++ 6 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 docs/backend-requests/making/machine.mdx create mode 100644 docs/backend-requests/resources/machine-tokens.mdx diff --git a/docs/backend-requests/handling/manual-jwt.mdx b/docs/backend-requests/handling/manual-jwt.mdx index bdb780d2f4..88827ba577 100644 --- a/docs/backend-requests/handling/manual-jwt.mdx +++ b/docs/backend-requests/handling/manual-jwt.mdx @@ -1,15 +1,23 @@ --- -title: Manual JWT verification -description: Learn how to manually verify Clerk-generated session tokens (JWTs). +title: Manual JWT Verification +description: Learn how to manually verify Clerk-generated session and machine tokens (JWTs). --- -Your Clerk-generated [session tokens](/docs/backend-requests/resources/session-tokens) are essentially JWTs which are signed using your instance's private key and can be verified using your instance's public key. Depending on your architecture, these tokens will be in your backend requests either via a cookie named `__session` or via the Authorization header. +## Verifying Tokens -For every request, you must validate its token to make sure it hasn't expired and it is authentic (i.e. no malicious user tried to tamper with it). If these validations pass, then it means that the user is authenticated to your application and you should consider them signed in. +Clerk-generated tokens, including [session tokens](/docs/backend-requests/resources/session-tokens) and [machine tokens](/docs/backend-requests/resources/machine-tokens), are JWTs signed using your instance's private key and can be verified using your instance's public key. -The `authenticateRequest()` method from the JavaScript Backend SDK does all of this for you. It accepts the `request` object and authenticates the session token in it. See the [reference page](/docs/references/backend/authenticate-request) for more information. +For every request, you must validate the token to ensure it hasn't expired and is authentic (i.e., no malicious user tried to tamper with it). If these validations pass, it means that the user or machine is authenticated to your application. -## Networkless token verification +The `authenticateRequest()` method from the JavaScript Backend SDK handles these validations for you. It accepts the `request` object and authenticates the token in it. See the [reference page](/docs/references/backend/authenticate-request) for more information. + +### Session Tokens + +Session tokens authenticate users. Depending on your architecture, these tokens will be in your backend requests either via a cookie named `__session` or via the Authorization header. + +If the token is valid, you can consider the user signed in to your application. + +#### Networkless token verification {/* Note: this example is duped from /authenticate-request. Probably a good opportunity to use a partial here */} @@ -38,3 +46,38 @@ export async function GET(req: Request) { return Response.json({ message: 'This is a reply' }) } ``` + +### Machine Tokens + +Machine tokens authenticate machines. They are typically provided via the Authorization header in your backend requests. + +If the token is valid, it means that the machine is authenticated to your application. + +To authenticate machine requests using `authenticateRequest()`, specify the `entity` parameter as `'machine'`. See the [reference page](/docs/references/backend/authenticate-request) for more information. + +The following example uses the `authenticateRequest()` method with the [JavaScript Backend SDK](/docs/references/backend/overview) to verify that the token is a valid machine token generated by Clerk. + + +```tsx +import { createClerkClient } from '@clerk/backend'; + +export async function GET(req: Request) { + const clerkClient = createClerkClient({ + secretKey: process.env.CLERK_SECRET_KEY, + publishableKey: process.env.CLERK_PUBLISHABLE_KEY, + }); + + const { isMachineAuthenticated, machinedId } = await clerkClient.authenticateRequest(req, { + entity: 'machine', + }); + + if (!authReq.isMachineAuthenticated) { + return Response.json({ status: 401 }); + } + + return Response.json({ + message: 'Machine is authenticated', + machineId + }); +} +``` diff --git a/docs/backend-requests/making/machine.mdx b/docs/backend-requests/making/machine.mdx new file mode 100644 index 0000000000..5261fa2115 --- /dev/null +++ b/docs/backend-requests/making/machine.mdx @@ -0,0 +1,45 @@ +--- +title: Making Machine Requests +description: Lean about making machine-to-machine requests. +--- + +If your client is a backend service, you can create a [machine token](/docs/backend-requests/resources/machine-tokens) and use it in the `Authorization` header of your request. + +## Using the Node.js SDK + +The Node.js SDK has a `machineTokens` object that can be used to create machine tokens. + +> [!WARNING] +> Use of the Node.js SDK is still subject to the [Backend API rate limits](/docs/backend-requests/resources/rate-limits) + +```tsx +import { createClerkClient } from '@clerk/backend' + +export default function machineFetch() { + + const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + + // creates a token with no additional claims. + const { token } = await clerkClient.machineTokens.create({ + machineId: "mch_cron", + claims: { + permissions: ["read", "write"] + }, // custom claims customer's can add to their token + expiresInSeconds: 60 + }); + + const authenticatedFetch = async (...args) => { + return fetch(...args, { + headers: { Authorization: `Bearer ${await getToken()}` }, + }).then((res) => res.json()) + } + + return authenticatedFetch +} +``` + +## Using the Backend API reference + +You can also generate machine tokens by simply making a requests to Clerk's Backend API + +Go to the Backend API reference to learn more. **The API reference for this endpoint doesn't exist yet** \ No newline at end of file diff --git a/docs/backend-requests/overview.mdx b/docs/backend-requests/overview.mdx index f083b3097c..573a8d5462 100644 --- a/docs/backend-requests/overview.mdx +++ b/docs/backend-requests/overview.mdx @@ -3,13 +3,14 @@ title: Request authentication description: Learn about various ways to make authenticated requests to the backend when using Clerk SDKs. --- -A request is considered “authenticated” when the backend can securely identify the user and device that is making the request. The reasons for making authenticated requests to the backend include: +A request is considered “authenticated” when the backend can securely identify the entity that is making the request. The reasons for making authenticated requests to the backend include: -- Associating the user with the action being performed +- Associating a user with the action being performed +- Associating a machine with the action being performed - Ensuring the user has permission to make the request - Keeping an audit log of which device the user is performing actions from -In order to authenticate the user on the backend using Clerk's SDK, the short-lived [session token](/docs/backend-requests/resources/session-tokens) needs to be passed to the server. +In order to authenticate a request on the backend using Clerk's SDK, a short-lived [session token](/docs/backend-requests/resources/session-tokens) or a [machine token](/docs/backend-requests/resources/machine-tokens) needs to be passed to the server. ## Frontend requests @@ -27,7 +28,7 @@ For same-origin requests, refer to our guide on [making same-origin requests](/d For cross-origin requests, refer to our guide on [making cross-origin requests](/docs/backend-requests/making/cross-origin). -## Backend requests +## Backend middleware Clerk provides various middleware packages to set the session property for easy access. These packages can also require a session to be available on the current request. Choose the guide based on the language or framework you're using: @@ -36,7 +37,13 @@ Clerk provides various middleware packages to set the session property for easy - [Go](/docs/backend-requests/handling/go) - [Ruby on Rails / Rack](/docs/backend-requests/handling/ruby-rails) -If there is not middleware available for your preferred language or framework, you can extract the session token manually. +If there is not middleware available for your preferred language or framework, you can extract the token manually. + +### Machine + +For machine requests, you need to create a machine token using Clerk's backend API. This token is similiar to a session token, but it allows you to authenticate backend requests without a user session. Include the machine token as a Bearer token in the `Authorization` header when making requests to your backend. + +You can learn more about [creating machine tokens](/docs/backend-requests/resources/machine-tokens) and [handling machine tokens](/docs/backend-requests/handling/manual-jwt#authenticating-machine-tokens) for additional information ### Same-origin diff --git a/docs/backend-requests/resources/machine-tokens.mdx b/docs/backend-requests/resources/machine-tokens.mdx new file mode 100644 index 0000000000..e018d9c624 --- /dev/null +++ b/docs/backend-requests/resources/machine-tokens.mdx @@ -0,0 +1,81 @@ +--- +title: Machine tokens +description: Learn about machine tokens and how to validate them in your backend. +--- + +When you want a machine to authenticate requests to your backend, you authorize the requests with machine tokens. + +Machine tokens are JWTs that contain information about your machine. + +## Customizing your machine tokens. + +### Machine ID + +Every machine token you create needs to be associated with a `machine_id`. You can pick any value for the `machine_id` as long as it meets the following requirements: + +- It must be prefixed with `mch_` +- It must only contain lowercase letters and numbers + +> [!TIP] +> It is a good idea to have the `machine_id` correspond with the identity of the service generating the token. For example if you have a cron service, a `machine_id` of `mch_cron` would make sense. + +#### Some valid machine_ids + +- mch_123 +- mch_hi_there_jack +- mch_ooooooooooohhhhhhhhhhhhh_snaaaaaaaaaaap + +#### Some invalid machine_ids + +- user_1234 +- mch_OH_HI_MARK +- MCH_123 +- mch-123 + +### Some **valid** machine_ids + +- mch_cron +- mch_pub_sub +- mch_scheduler +- mch_device_ada3f8b7-d491-4fe4-b76e-99e4c00b56d1 + +### Claims + +You can add custom claims to your machine token to include any additional information that your application might need. Claims are key-value pairs included in the token's payload, and they can convey important data such as permissions, roles, or any other attributes relevant to the machine's identity. + +For example, it is a good practice to include any permissions that your service requires directly in the claims. This allows your backend to easily verify what actions the machine is authorized to perform. + +> [!NOTE] +> You cannot add claims that are [already set by clerk](#default-machine-claims). + +### Expires In Seconds + +The `expiresInSeconds` parameter defines how long the machine token remains valid, specified in seconds. This parameter is optional and defaults to 60 seconds (1 minute). + +If you need the machine token to be valid for a longer period of time, you can set the `expiresInSeconds` parameter to a higher value. However, keep in mind that longer-lived tokens can present a higher security risk if compromised, while shorter-lived tokens may require more frequent token generation, potentially impacting your [Backend API rate limits](/docs/backend-requests/resources/rate-limits). Therefore, it's important to balance token lifespan with security requirements and rate limit considerations. + +### Clock Skew + +The `allowedClockSkew` parameter provides a leeway in seconds to account for clock differences between servers. This setting affects the `nbf` (Not Before) claim in the token, calculated as `nbf = current_time - allowed_clock_skew`. The default value is 5 seconds. + +Adjusting the clock skew helps prevent token validation failures due to minor time discrepancies between the issuing server and the verifying server. + + +## Default machine claims + +Every generated token has default claims that cannot be overridden by custom claims. Clerk's default claims include: + +- `exp`: expiration time - the time after which the token will expire, as a Unix timestamp. Determined using the **Token Expires In Seconds** request body parameter when creating machine tokens. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4) for more information. +- `iat`: issued at - the time at which the token was issued as a Unix timestamp. For example: `1516239022`. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6) for more information. +- `jti`: JWT ID - the ID of the token internally generated by Clerk. For example: `a1b2c3d4e5f67890abcd`. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7) for more information. +- `iss`: issuer - the Frontend API URL of your instance. For example: `https://clerk.your-site.com` for a production instance or `https://your-site.clerk.accounts.dev` for a development instance. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1) for more information. +- `nbf`: not before - the time before which the token is considered invalid, as a Unix timestamp. Determined using the **Allowed Clock Skew** request body parameter when creating machine tokens. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5) for more information. +- `sub`: subject - the ID of the machine that created the token. Determined using the **Machine ID** request body parameter when creating machine tokens. For example: `mch_123`. See [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2) for more information. + +## Making Machine Requests + +To start making machine requests, refer to [making machine requests](/docs/backend-requests/making/machine). + +## Validating Machine Tokens + +To learn how to manually verify a machine token, refer to [validating machine tokens](/docs/backend-requests/handling/manual-jwt#machine-tokens). \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index 4ab96626aa..1851f63623 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -697,6 +697,10 @@ { "title": "JWT Templates", "href": "/docs/backend-requests/making/jwt-templates" + }, + { + "title": "Machine Requests", + "href": "/docs/backend-requests/making/machine" } ] ] @@ -753,6 +757,10 @@ "title": "Session tokens", "href": "/docs/backend-requests/resources/session-tokens" }, + { + "title": "Machine tokens", + "href": "/docs/backend-requests/resources/machine-tokens" + }, { "title": "Rate limits", "href": "/docs/backend-requests/resources/rate-limits" diff --git a/docs/references/backend/authenticate-request.mdx b/docs/references/backend/authenticate-request.mdx index debdc96f42..a40d141739 100644 --- a/docs/references/backend/authenticate-request.mdx +++ b/docs/references/backend/authenticate-request.mdx @@ -61,6 +61,13 @@ It is recommended to set these options as [environment variables](/docs/deployme --- + - 'entity?' + - 'session' | 'machine' + + Determines what type of authentication to perform. If set to `'session'`, the function will authenticate a user session. If set to `'machine'`, the function will authenticate a machine-to-machine request. Defaults to `session` + + --- + - `domain?` - `string` @@ -225,3 +232,31 @@ export async function GET(req: Request) { return Response.json({ message: 'This is a reply' }) } ``` + +### Machine token verifications + +The following example uses the `authenticateRequest()` to verify a machine token. + +```tsx +import { createClerkClient } from '@clerk/backend'; + +export async function GET(req: Request) { + const clerkClient = createClerkClient({ + secretKey: process.env.CLERK_SECRET_KEY, + publishableKey: process.env.CLERK_PUBLISHABLE_KEY, + }); + + const { isMachineAuthenticated, machinedId } = await clerkClient.authenticateRequest(req, { + entity: 'machine', + }); + + if (!authReq.isMachineAuthenticated) { + return Response.json({ status: 401 }); + } + + return Response.json({ + message: 'Machine is authenticated', + machineId + }); +} +``` \ No newline at end of file