-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(examples): Added example apps for Clerk integration (#244)
Adds example apps for integrating Arcjet with Clerk.
- Loading branch information
1 parent
f495f1b
commit 95c7abd
Showing
40 changed files
with
11,698 additions
and
10 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 |
---|---|---|
|
@@ -131,3 +131,6 @@ dist | |
|
||
# One-off scripts | ||
*.sh | ||
|
||
# macOS | ||
.DS_Store |
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 |
---|---|---|
|
@@ -2,12 +2,12 @@ | |
# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml | ||
version: 0.1 | ||
cli: | ||
version: 1.19.0 | ||
version: 1.20.0 | ||
# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) | ||
plugins: | ||
sources: | ||
- id: trunk | ||
ref: v1.4.2 | ||
ref: v1.4.3 | ||
uri: https://github.com/trunk-io/plugins | ||
# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) | ||
runtimes: | ||
|
@@ -20,17 +20,17 @@ lint: | |
enabled: | ||
- [email protected] | ||
- [email protected] | ||
- trivy@0.48.2 | ||
- yamllint@1.33.0 | ||
- semgrep@1.55.2 | ||
- [email protected].1 | ||
- trivy@0.49.1 | ||
- yamllint@1.35.1 | ||
- semgrep@1.61.1 | ||
- [email protected].2 | ||
- [email protected] | ||
- git-diff-check | ||
- markdownlint@0.38.0 | ||
- osv-scanner@1.5.0 | ||
- prettier@3.1.1 | ||
- markdownlint@0.39.0 | ||
- osv-scanner@1.6.2 | ||
- prettier@3.2.5 | ||
- [email protected] | ||
- trufflehog@3.63.7 | ||
- trufflehog@3.67.6 | ||
disabled: | ||
# tfsec and checkov are replaced by Trivy | ||
- tfsec | ||
|
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,5 @@ | ||
# Get your Arcjet key from https://app.arcjet.com | ||
ARCJET_KEY= | ||
# Get your Clerk keys from https://clerk.com/docs/quickstarts/nextjs | ||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY= | ||
CLERK_SECRET_KEY= |
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,3 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
} |
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,36 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
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 @@ | ||
omit=optional |
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,45 @@ | ||
<a href="https://arcjet.com" target="_arcjet-home"> | ||
<picture> | ||
<source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/arcjet-logo-minimal-dark-mark-all.svg"> | ||
<img src="https://arcjet.com/arcjet-logo-minimal-light-mark-all.svg" alt="Arcjet Logo" height="128" width="auto"> | ||
</picture> | ||
</a> | ||
|
||
# Arcjet Rate Limit / Clerk Authentication Example | ||
|
||
This example shows how to use an Arcjet rate limit with a user ID from [Clerk | ||
authentication and Next.js](https://clerk.com/docs/quickstarts/nextjs). | ||
|
||
It sets up 2 API routes: | ||
|
||
* `/api/public` does not require authentication and has a low rate limit based | ||
on the user IP address. | ||
* `/api/private` uses Clerk authentication and has a higher rate limit based on | ||
the Clerk user ID. | ||
|
||
## How to use | ||
|
||
1. From the root of the project, install the SDK dependencies. | ||
|
||
```bash | ||
npm ci | ||
``` | ||
|
||
2. Enter this directory and install the example's dependencies. | ||
|
||
```bash | ||
cd examples/nextjs-14-clerk-rl | ||
npm ci | ||
``` | ||
|
||
3. Rename `.env.local.example` to `.env.local` and add your Arcjet and Clerk | ||
keys. | ||
|
||
4. Start the dev server. | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
5. Visit `http://localhost:3000`. | ||
6. Try the different routes linked on the page. |
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,59 @@ | ||
/** | ||
* Testing this route requires a Clerk user JWT token passed in the | ||
* Authorization header. | ||
* | ||
* `curl -v http://localhost:3000/api/private -H "Authorization: Bearer TOKENHERE"` | ||
* | ||
* Get the token from the /api/token route. | ||
*/ | ||
import arcjet, { tokenBucket } from "@arcjet/next"; | ||
import { NextResponse } from "next/server"; | ||
import { currentUser } from "@clerk/nextjs"; | ||
|
||
// The arcjet instance is created outside of the handler | ||
const aj = arcjet({ | ||
// Get your site key from https://app.arcjet.com | ||
// and set it as an environment variable rather than hard coding. | ||
// See: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables | ||
key: process.env.ARCJET_KEY!, | ||
rules: [ | ||
// Create a token bucket rate limit. Fixed and sliding window rate limits | ||
// are also supported. See https://docs.arcjet.com/rate-limiting/algorithms | ||
tokenBucket({ | ||
mode: "LIVE", // will block requests at the limit. Use "DRY_RUN" to log only | ||
// Rate limit based on the Clerk userId | ||
// See https://clerk.com/docs/references/nextjs/authentication-object | ||
// See https://docs.arcjet.com/rate-limiting/configuration#characteristics | ||
characteristics: ["userId"], | ||
refillRate: 5, // refill 5 tokens per interval | ||
interval: 10, // refill every 10 seconds | ||
capacity: 10, // bucket maximum capacity of 10 tokens | ||
}), | ||
], | ||
}); | ||
|
||
export async function GET(req: Request) { | ||
// Get the current user from Clerk | ||
// See https://clerk.com/docs/references/nextjs/current-user | ||
const user = await currentUser(); | ||
if (!user) { | ||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); | ||
} | ||
|
||
// Deduct 5 tokens from the user's bucket | ||
const decision = await aj.protect(req, { userId: user.id, requested: 5 }); | ||
|
||
if (decision.isDenied()) { | ||
return NextResponse.json( | ||
{ | ||
error: "Too Many Requests", | ||
reason: decision.reason, | ||
}, | ||
{ | ||
status: 429, | ||
} | ||
); | ||
} | ||
|
||
return NextResponse.json({ message: "Hello World" }); | ||
} |
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,42 @@ | ||
import arcjet, { tokenBucket } from "@arcjet/next"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// The arcjet instance is created outside of the handler | ||
const aj = arcjet({ | ||
// Get your site key from https://app.arcjet.com | ||
// and set it as an environment variable rather than hard coding. | ||
// See: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables | ||
key: process.env.ARCJET_KEY!, | ||
rules: [ | ||
// Create a token bucket rate limit. Fixed and sliding window rate limits | ||
// are also supported. See https://docs.arcjet.com/rate-limiting/algorithms | ||
tokenBucket({ | ||
mode: "LIVE", // will block requests at the limit. Use "DRY_RUN" to log only | ||
// Use the built in ip.src characteristic | ||
// See https://docs.arcjet.com/rate-limiting/configuration#characteristics | ||
characteristics: ["ip.src"], | ||
refillRate: 5, // refill 5 tokens per interval | ||
interval: 10, // refill every 10 seconds | ||
capacity: 10, // bucket maximum capacity of 10 tokens | ||
}), | ||
], | ||
}); | ||
|
||
export async function GET(req: Request) { | ||
// Deduct 5 tokens from the bucket | ||
const decision = await aj.protect(req, { requested: 5 }); | ||
|
||
if (decision.isDenied()) { | ||
return NextResponse.json( | ||
{ | ||
error: "Too Many Requests", | ||
reason: decision.reason, | ||
}, | ||
{ | ||
status: 429, | ||
} | ||
); | ||
} | ||
|
||
return NextResponse.json({ message: "Hello World" }); | ||
} |
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,21 @@ | ||
/** | ||
* This retrieves the Clerk JWT token for the current user so you can test the | ||
* private API route. | ||
*/ | ||
import { auth } from "@clerk/nextjs"; | ||
|
||
export async function GET(req: Request) { | ||
const { userId, getToken } = auth(); | ||
|
||
if (!userId) { | ||
return new Response("Unauthorized", { status: 401 }); | ||
} | ||
|
||
try { | ||
const token = await getToken(); | ||
|
||
return Response.json({ token }); | ||
} catch (error) { | ||
return Response.json(error); | ||
} | ||
} |
Binary file not shown.
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,95 @@ | ||
:root { | ||
--max-width: 1100px; | ||
--border-radius: 12px; | ||
--font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", | ||
"Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", | ||
"Fira Mono", "Droid Sans Mono", "Courier New", monospace; | ||
|
||
--foreground-rgb: 0, 0, 0; | ||
--background-start-rgb: 214, 219, 220; | ||
--background-end-rgb: 255, 255, 255; | ||
|
||
--primary-glow: conic-gradient(from 180deg at 50% 50%, | ||
#16abff33 0deg, | ||
#0885ff33 55deg, | ||
#54d6ff33 120deg, | ||
#0071ff33 160deg, | ||
transparent 360deg); | ||
--secondary-glow: radial-gradient(rgba(255, 255, 255, 1), | ||
rgba(255, 255, 255, 0)); | ||
|
||
--tile-start-rgb: 239, 245, 249; | ||
--tile-end-rgb: 228, 232, 233; | ||
--tile-border: conic-gradient(#00000080, | ||
#00000040, | ||
#00000030, | ||
#00000020, | ||
#00000010, | ||
#00000010, | ||
#00000080); | ||
|
||
--callout-rgb: 238, 240, 241; | ||
--callout-border-rgb: 172, 175, 176; | ||
--card-rgb: 180, 185, 188; | ||
--card-border-rgb: 131, 134, 135; | ||
} | ||
|
||
@media (prefers-color-scheme: dark) { | ||
:root { | ||
--foreground-rgb: 255, 255, 255; | ||
--background-start-rgb: 0, 0, 0; | ||
--background-end-rgb: 0, 0, 0; | ||
|
||
--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); | ||
--secondary-glow: linear-gradient(to bottom right, | ||
rgba(1, 65, 255, 0), | ||
rgba(1, 65, 255, 0), | ||
rgba(1, 65, 255, 0.3)); | ||
|
||
--tile-start-rgb: 2, 13, 46; | ||
--tile-end-rgb: 2, 5, 19; | ||
--tile-border: conic-gradient(#ffffff80, | ||
#ffffff40, | ||
#ffffff30, | ||
#ffffff20, | ||
#ffffff10, | ||
#ffffff10, | ||
#ffffff80); | ||
|
||
--callout-rgb: 20, 20, 20; | ||
--callout-border-rgb: 108, 108, 108; | ||
--card-rgb: 100, 100, 100; | ||
--card-border-rgb: 200, 200, 200; | ||
} | ||
} | ||
|
||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
html, | ||
body { | ||
max-width: 100vw; | ||
overflow-x: hidden; | ||
} | ||
|
||
body { | ||
color: rgb(var(--foreground-rgb)); | ||
background: linear-gradient(to bottom, | ||
transparent, | ||
rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb)); | ||
} | ||
|
||
a { | ||
color: inherit; | ||
} | ||
|
||
a:hover { | ||
text-decoration: none; | ||
} | ||
|
||
@media (prefers-color-scheme: dark) { | ||
html { | ||
color-scheme: dark; | ||
} | ||
} |
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,25 @@ | ||
import { ClerkProvider } from "@clerk/nextjs"; | ||
import type { Metadata } from "next"; | ||
import { Inter } from "next/font/google"; | ||
import "./globals.css"; | ||
|
||
const inter = Inter({ subsets: ["latin"] }); | ||
|
||
export const metadata: Metadata = { | ||
title: "Create Next App", | ||
description: "Generated by create next app", | ||
}; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<ClerkProvider> | ||
<html lang="en"> | ||
<body className={inter.className}>{children}</body> | ||
</html> | ||
</ClerkProvider> | ||
); | ||
} |
Oops, something went wrong.