Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/eight-walls-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/express': patch
---

Deprecates `enableHandshake` option in `clerkMiddleware` as it's not relevant for API requests. Handshake flow only applies to server-rendered applications with page navigation, not API endpoints. This option will be removed in a future version.
4 changes: 3 additions & 1 deletion integration/presets/express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { linkPackage } from './utils';
const vite = applicationConfig()
.setName('express-vite')
.useTemplate(templates['express-vite'])
.setEnvFormatter('public', key => `VITE_${key}`)
.addScript('setup', 'pnpm install')
.addScript('dev', 'pnpm dev')
.addScript('build', 'pnpm build')
.addScript('serve', 'pnpm start')
.addDependency('@clerk/express', constants.E2E_CLERK_VERSION || linkPackage('express'));
.addDependency('@clerk/express', constants.E2E_CLERK_VERSION || linkPackage('express'))
.addDependency('@clerk/clerk-js', constants.E2E_CLERK_VERSION || linkPackage('clerk-js'));

export const express = {
vite,
Expand Down
13 changes: 13 additions & 0 deletions integration/templates/express-vite/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS + Express</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/client/main.ts"></script>
</body>
</html>
22 changes: 10 additions & 12 deletions integration/templates/express-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@
"private": true,
"scripts": {
"build": "vite build",
"dev": "PORT=$PORT ts-node src/server/main.ts",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"dev": "PORT=$PORT tsx src/server/main.ts",
"preview": "vite preview --port $PORT --no-open",
"start": "PORT=$PORT ts-node src/server/main.ts"
"start": "PORT=$PORT NODE_ENV=production tsx src/server/main.ts"
},
"dependencies": {
"dotenv": "^16.4.7",
"ejs": "^3.1.6",
"express": "^4.18.2",
"ts-node": "^10.9.1",
"vite-express": "^0.20.0"
"dotenv": "^17.2.1",
"express": "^5.1.0",
"tsx": "^4.20.3",
"vite-express": "^0.21.1"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^20.9.3",
"typescript": "^5.7.3",
"vite": "^5.0.2"
"@types/express": "^5.0.3",
"@types/node": "^24.2.1",
"typescript": "^5.8.3",
"vite": "^6.3.3"
}
}
26 changes: 26 additions & 0 deletions integration/templates/express-vite/src/client/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Clerk } from '@clerk/clerk-js';

const publishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;

document.addEventListener('DOMContentLoaded', async function () {
const clerk = new Clerk(publishableKey);
await clerk.load();

if (clerk.isSignedIn) {
document.getElementById('app')!.innerHTML = `
<div id="user-button"></div>
`;

const userButtonDiv = document.getElementById('user-button');

clerk.mountUserButton(userButtonDiv);
} else {
document.getElementById('app')!.innerHTML = `
<div id="sign-in"></div>
`;

const signInDiv = document.getElementById('sign-in');

clerk.mountSignIn(signInDiv);
}
});
7 changes: 7 additions & 0 deletions integration/templates/express-vite/src/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
59 changes: 20 additions & 39 deletions integration/templates/express-vite/src/server/main.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,44 @@
// Should be at the top of the file - used to load clerk secret key
import 'dotenv/config';

import { clerkMiddleware } from '@clerk/express';
import { clerkMiddleware, getAuth } from '@clerk/express';
import express from 'express';
import ViteExpress from 'vite-express';

const app = express();

app.use(clerkMiddleware());
app.set('view engine', 'ejs');
app.set('views', 'src/views');
app.use(
clerkMiddleware({
publishableKey: process.env.VITE_CLERK_PUBLISHABLE_KEY,
}),
);

app.get('/api/protected', (req: any, res: any, _next: any) => {
const { userId } = getAuth(req);
if (!userId) {
res.status(401).send('Unauthorized');
return;
}

res.send('Protected API response');
});

const legacyRequireAuth = (req: any, _res: any, next: any) => {
if (!req.auth.userId) {
return next(new Error('Unauthenticated'));
return next(new Error('Unauthorized'));
}

next();
};

app.get('/api/protected', legacyRequireAuth, (_req: any, res: any, _next: any) => {
return res.send('Protected API response');
});

app.get('/sign-in', (_req: any, res: any) => {
return res.render('sign-in.ejs', {
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
signInUrl: process.env.CLERK_SIGN_IN_URL,
});
});

app.get('/', (_req: any, res: any) => {
return res.render('index.ejs', {
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
signInUrl: process.env.CLERK_SIGN_IN_URL,
});
});

app.get('/sign-up', (_req: any, res: any) => {
return res.render('sign-up.ejs', {
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
signUpUrl: process.env.CLERK_SIGN_UP_URL,
});
});

app.get('/protected', (_req: any, res: any) => {
return res.render('protected.ejs', {
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
signInUrl: process.env.CLERK_SIGN_IN_URL,
signUpUrl: process.env.CLERK_SIGN_UP_URL,
});
app.get('/api/legacy/protected', legacyRequireAuth, (_req: any, res: any, _next: any) => {
res.send('Protected API response');
});

// Handle authentication error, otherwise application will crash
// @ts-ignore
app.use((err, req, res, next) => {
if (err) {
console.error(err);
res.status(401).end();
res.status(401).send('Unauthorized');
return;
}

Expand Down
32 changes: 0 additions & 32 deletions integration/templates/express-vite/src/views/index.ejs

This file was deleted.

32 changes: 0 additions & 32 deletions integration/templates/express-vite/src/views/protected.ejs

This file was deleted.

24 changes: 0 additions & 24 deletions integration/templates/express-vite/src/views/sign-in.ejs

This file was deleted.

24 changes: 0 additions & 24 deletions integration/templates/express-vite/src/views/sign-up.ejs

This file was deleted.

18 changes: 9 additions & 9 deletions integration/templates/express-vite/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"module": "NodeNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "NodeNext",
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "CommonJS",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"skipLibCheck": true
},
"include": ["src"]
}
4 changes: 0 additions & 4 deletions integration/templates/express-vite/vite.config.ts

This file was deleted.

Loading
Loading