From 546622e0ea7c5a8a6ab63d1879c87c9b0007b87e Mon Sep 17 00:00:00 2001 From: Mohamed Melouk <42706279+cobraprojects@users.noreply.github.com> Date: Mon, 11 May 2026 20:44:27 +0300 Subject: [PATCH 1/3] clerk auth --- apps/blog-next/.env.example | 2 +- .../app/api/auth/clerk/callback/route.ts | 10 + .../app/api/auth/clerk/login/route.ts | 5 + .../app/api/auth/clerk/logout/route.ts | 10 + .../app/api/auth/clerk/register/route.ts | 5 + apps/blog-next/app/auth-nav.tsx | 3 + apps/blog-next/app/login/page.tsx | 1 + apps/blog-next/app/register/page.tsx | 1 + apps/blog-next/config/auth.ts | 5 +- apps/blog-nuxt/.env.example | 2 +- apps/blog-nuxt/app/app.vue | 3 + apps/blog-nuxt/app/pages/login/index.vue | 1 + apps/blog-nuxt/app/pages/register/index.vue | 1 + apps/blog-nuxt/config/auth.ts | 5 +- .../server/api/auth/clerk/callback.get.ts | 12 + .../server/api/auth/clerk/login.get.ts | 5 + .../server/api/auth/clerk/logout.post.ts | 14 + .../server/api/auth/clerk/register.get.ts | 5 + apps/blog-sveltekit/.env.example | 2 +- apps/blog-sveltekit/config/auth.ts | 5 +- apps/blog-sveltekit/src/routes/+layout.svelte | 3 + .../routes/api/auth/clerk/callback/+server.ts | 11 + .../routes/api/auth/clerk/login/+server.ts | 6 + .../routes/api/auth/clerk/logout/+server.ts | 11 + .../routes/api/auth/clerk/register/+server.ts | 6 + .../src/routes/login/+page.svelte | 1 + .../src/routes/register/+page.svelte | 1 + apps/docs/docs/auth/clerk.md | 197 ++-- bun.lock | 605 +++++++----- package.json | 113 ++- packages/adapter-next/package.json | 16 +- packages/adapter-next/src/runtime.ts | 8 + packages/adapter-nuxt/package.json | 21 +- .../src/runtime/composables/index.ts | 20 + packages/adapter-sveltekit/package.json | 14 +- packages/adapter-sveltekit/src/index.ts | 8 + packages/auth-clerk/package.json | 13 +- packages/auth-clerk/src/contracts.ts | 48 +- packages/auth-clerk/src/index.ts | 917 +++++++++++++++--- packages/auth-clerk/src/jwt.ts | 19 - packages/auth-clerk/tests/package.test.ts | 397 +++++++- packages/auth-social-apple/package.json | 10 +- packages/auth-social-discord/package.json | 10 +- packages/auth-social-facebook/package.json | 10 +- packages/auth-social-github/package.json | 10 +- packages/auth-social-google/package.json | 10 +- packages/auth-social-linkedin/package.json | 10 +- packages/auth-social/package.json | 10 +- packages/auth-workos/package.json | 12 +- packages/auth/package.json | 6 +- packages/auth/src/contracts.ts | 1 + packages/auth/src/runtime.ts | 4 + packages/auth/src/runtime/requestAccess.ts | 56 ++ packages/auth/src/runtime/responseCookies.ts | 4 +- packages/authorization/package.json | 6 +- packages/broadcast/package.json | 14 +- packages/cache-db/package.json | 10 +- packages/cache-redis/package.json | 12 +- packages/cache/package.json | 8 +- packages/cli/package.json | 20 +- .../cli/src/generated/workspaceCatalog.ts | 4 +- packages/cli/src/project.ts | 2 + packages/cli/src/project/scaffold.ts | 28 +- .../src/project/scaffold/config-renderers.ts | 3 +- .../project/scaffold/framework-renderers.ts | 255 ++++- .../cli/src/project/scaffold/framework.ts | 1 + .../src/project/scaffold/project-renderers.ts | 2 +- packages/cli/tests/cli.test.ts | 9 +- packages/config/package.json | 6 +- packages/config/src/defaults.ts | 69 +- packages/config/src/index.ts | 4 + packages/config/src/types.ts | 18 +- packages/config/tests/config.test.ts | 39 +- packages/core/package.json | 50 +- packages/core/src/portable/holo.ts | 8 + packages/create-holo-js/package.json | 8 +- packages/db-mysql/package.json | 10 +- packages/db-postgres/package.json | 12 +- packages/db-sqlite/package.json | 12 +- packages/db/package.json | 20 +- packages/events/package.json | 10 +- packages/flux-react/package.json | 20 +- packages/flux-svelte/package.json | 14 +- packages/flux-vue/package.json | 14 +- packages/flux/package.json | 8 +- packages/forms/package.json | 10 +- packages/mail/package.json | 14 +- packages/media/package.json | 12 +- packages/notifications/package.json | 10 +- packages/queue-db/package.json | 10 +- packages/queue-redis/package.json | 14 +- packages/queue/package.json | 10 +- packages/security/package.json | 8 +- packages/session/package.json | 8 +- packages/storage-s3/package.json | 6 +- packages/storage/package.json | 12 +- packages/validation/package.json | 8 +- scripts/publish-with-resolved-catalogs.mjs | 104 ++ .../publish-with-resolved-catalogs.test.mjs | 90 ++ .../validate-dependency-version-policy.mjs | 75 +- ...alidate-dependency-version-policy.test.mjs | 58 +- 101 files changed, 2932 insertions(+), 898 deletions(-) create mode 100644 apps/blog-next/app/api/auth/clerk/callback/route.ts create mode 100644 apps/blog-next/app/api/auth/clerk/login/route.ts create mode 100644 apps/blog-next/app/api/auth/clerk/logout/route.ts create mode 100644 apps/blog-next/app/api/auth/clerk/register/route.ts create mode 100644 apps/blog-nuxt/server/api/auth/clerk/callback.get.ts create mode 100644 apps/blog-nuxt/server/api/auth/clerk/login.get.ts create mode 100644 apps/blog-nuxt/server/api/auth/clerk/logout.post.ts create mode 100644 apps/blog-nuxt/server/api/auth/clerk/register.get.ts create mode 100644 apps/blog-sveltekit/src/routes/api/auth/clerk/callback/+server.ts create mode 100644 apps/blog-sveltekit/src/routes/api/auth/clerk/login/+server.ts create mode 100644 apps/blog-sveltekit/src/routes/api/auth/clerk/logout/+server.ts create mode 100644 apps/blog-sveltekit/src/routes/api/auth/clerk/register/+server.ts create mode 100644 scripts/publish-with-resolved-catalogs.mjs create mode 100644 scripts/publish-with-resolved-catalogs.test.mjs diff --git a/apps/blog-next/.env.example b/apps/blog-next/.env.example index d382e1b1..023507f7 100644 --- a/apps/blog-next/.env.example +++ b/apps/blog-next/.env.example @@ -48,9 +48,9 @@ WORKOS_REDIRECT_URI= WORKOS_SESSION_COOKIE= CLERK_PUBLISHABLE_KEY= CLERK_SECRET_KEY= -CLERK_JWT_KEY= CLERK_API_URL= CLERK_FRONTEND_API= +CLERK_REDIRECT_URI= CLERK_SESSION_COOKIE= BROADCAST_CONNECTION=holo diff --git a/apps/blog-next/app/api/auth/clerk/callback/route.ts b/apps/blog-next/app/api/auth/clerk/callback/route.ts new file mode 100644 index 00000000..edc32ac5 --- /dev/null +++ b/apps/blog-next/app/api/auth/clerk/callback/route.ts @@ -0,0 +1,10 @@ +import { completeClerkAuth } from '@holo-js/auth-clerk' + +export async function GET(request: Request) { + const result = await completeClerkAuth(request) + if (!result.ok) { + return Response.redirect(new URL(`/login?error=${encodeURIComponent(result.code)}`, request.url)) + } + + return Response.redirect(new URL('/admin', request.url)) +} diff --git a/apps/blog-next/app/api/auth/clerk/login/route.ts b/apps/blog-next/app/api/auth/clerk/login/route.ts new file mode 100644 index 00000000..c130bdd4 --- /dev/null +++ b/apps/blog-next/app/api/auth/clerk/login/route.ts @@ -0,0 +1,5 @@ +import { loginWithClerk } from '@holo-js/auth-clerk' + +export async function GET(request: Request) { + return await loginWithClerk(request) +} diff --git a/apps/blog-next/app/api/auth/clerk/logout/route.ts b/apps/blog-next/app/api/auth/clerk/logout/route.ts new file mode 100644 index 00000000..68a0d190 --- /dev/null +++ b/apps/blog-next/app/api/auth/clerk/logout/route.ts @@ -0,0 +1,10 @@ +import { logoutWithClerk } from '@holo-js/auth-clerk' + +export async function POST(request: Request) { + const result = await logoutWithClerk(request) + if (!result.ok) { + return Response.json(result, { status: 422 }) + } + + return Response.redirect(result.url, 303) +} diff --git a/apps/blog-next/app/api/auth/clerk/register/route.ts b/apps/blog-next/app/api/auth/clerk/register/route.ts new file mode 100644 index 00000000..92861dab --- /dev/null +++ b/apps/blog-next/app/api/auth/clerk/register/route.ts @@ -0,0 +1,5 @@ +import { registerWithClerk } from '@holo-js/auth-clerk' + +export async function GET(request: Request) { + return await registerWithClerk(request) +} diff --git a/apps/blog-next/app/auth-nav.tsx b/apps/blog-next/app/auth-nav.tsx index 61dcd30d..82a76be2 100644 --- a/apps/blog-next/app/auth-nav.tsx +++ b/apps/blog-next/app/auth-nav.tsx @@ -64,6 +64,9 @@ export function AuthNav() {
+
+ +
) } diff --git a/apps/blog-next/app/login/page.tsx b/apps/blog-next/app/login/page.tsx index 5b5c7f2d..ca3826a8 100644 --- a/apps/blog-next/app/login/page.tsx +++ b/apps/blog-next/app/login/page.tsx @@ -48,6 +48,7 @@ export default function LoginPage() { Continue with Google Continue with GitHub Continue with WorkOS + Continue with Clerk
{ event.preventDefault(); form.submit() }} style={{ display: 'grid', gap: '0.9rem' }}> diff --git a/apps/blog-next/app/register/page.tsx b/apps/blog-next/app/register/page.tsx index 168396d9..4ce55e32 100644 --- a/apps/blog-next/app/register/page.tsx +++ b/apps/blog-next/app/register/page.tsx @@ -101,6 +101,7 @@ export default function RegisterPage() { Already have an account? Register with WorkOS + Register with Clerk ) } diff --git a/apps/blog-next/config/auth.ts b/apps/blog-next/config/auth.ts index b54d336e..c1ec02f4 100644 --- a/apps/blog-next/config/auth.ts +++ b/apps/blog-next/config/auth.ts @@ -65,13 +65,14 @@ export default defineAuthConfig({ }, // Add a dedicated guard and provider if WorkOS users should resolve through a different model. clerk: { + provider: env('AUTH_CLERK_PROVIDER', 'app'), app: { publishableKey: env('CLERK_PUBLISHABLE_KEY'), secretKey: env('CLERK_SECRET_KEY'), - jwtKey: env('CLERK_JWT_KEY'), apiUrl: env('CLERK_API_URL'), frontendApi: env('CLERK_FRONTEND_API'), - sessionCookie: env('CLERK_SESSION_COOKIE', "__session"), + redirectUri: env('CLERK_REDIRECT_URI'), + sessionCookie: env('CLERK_SESSION_COOKIE', '__session'), }, }, // Add a dedicated guard and provider if Clerk users should resolve through a different model. diff --git a/apps/blog-nuxt/.env.example b/apps/blog-nuxt/.env.example index d382e1b1..023507f7 100644 --- a/apps/blog-nuxt/.env.example +++ b/apps/blog-nuxt/.env.example @@ -48,9 +48,9 @@ WORKOS_REDIRECT_URI= WORKOS_SESSION_COOKIE= CLERK_PUBLISHABLE_KEY= CLERK_SECRET_KEY= -CLERK_JWT_KEY= CLERK_API_URL= CLERK_FRONTEND_API= +CLERK_REDIRECT_URI= CLERK_SESSION_COOKIE= BROADCAST_CONNECTION=holo diff --git a/apps/blog-nuxt/app/app.vue b/apps/blog-nuxt/app/app.vue index 3f5562c6..7fe6da32 100644 --- a/apps/blog-nuxt/app/app.vue +++ b/apps/blog-nuxt/app/app.vue @@ -24,6 +24,9 @@ async function logout() {
+
+ +
diff --git a/apps/blog-nuxt/config/auth.ts b/apps/blog-nuxt/config/auth.ts index b54d336e..c1ec02f4 100644 --- a/apps/blog-nuxt/config/auth.ts +++ b/apps/blog-nuxt/config/auth.ts @@ -65,13 +65,14 @@ export default defineAuthConfig({ }, // Add a dedicated guard and provider if WorkOS users should resolve through a different model. clerk: { + provider: env('AUTH_CLERK_PROVIDER', 'app'), app: { publishableKey: env('CLERK_PUBLISHABLE_KEY'), secretKey: env('CLERK_SECRET_KEY'), - jwtKey: env('CLERK_JWT_KEY'), apiUrl: env('CLERK_API_URL'), frontendApi: env('CLERK_FRONTEND_API'), - sessionCookie: env('CLERK_SESSION_COOKIE', "__session"), + redirectUri: env('CLERK_REDIRECT_URI'), + sessionCookie: env('CLERK_SESSION_COOKIE', '__session'), }, }, // Add a dedicated guard and provider if Clerk users should resolve through a different model. diff --git a/apps/blog-nuxt/server/api/auth/clerk/callback.get.ts b/apps/blog-nuxt/server/api/auth/clerk/callback.get.ts new file mode 100644 index 00000000..c33a61ac --- /dev/null +++ b/apps/blog-nuxt/server/api/auth/clerk/callback.get.ts @@ -0,0 +1,12 @@ +import { completeClerkAuth } from '@holo-js/auth-clerk' +import { sendRedirect } from 'h3' + +export default defineEventHandler(async (event) => { + const result = await completeClerkAuth(event) + if (!result.ok) { + const errCode = result.code ?? 'unknown_error' + return await sendRedirect(event, `/login?error=${encodeURIComponent(errCode)}`, 303) + } + + return await sendRedirect(event, '/admin', 303) +}) diff --git a/apps/blog-nuxt/server/api/auth/clerk/login.get.ts b/apps/blog-nuxt/server/api/auth/clerk/login.get.ts new file mode 100644 index 00000000..0d860cfe --- /dev/null +++ b/apps/blog-nuxt/server/api/auth/clerk/login.get.ts @@ -0,0 +1,5 @@ +import { loginWithClerk } from '@holo-js/auth-clerk' + +export default defineEventHandler(async (event) => { + return await loginWithClerk(event) +}) diff --git a/apps/blog-nuxt/server/api/auth/clerk/logout.post.ts b/apps/blog-nuxt/server/api/auth/clerk/logout.post.ts new file mode 100644 index 00000000..ce54e6a1 --- /dev/null +++ b/apps/blog-nuxt/server/api/auth/clerk/logout.post.ts @@ -0,0 +1,14 @@ +import { logoutWithClerk } from '@holo-js/auth-clerk' +import { createError, sendRedirect } from 'h3' + +export default defineEventHandler(async (event) => { + const result = await logoutWithClerk(event) + if (!result.ok) { + throw createError({ + statusCode: 422, + statusMessage: result.message, + }) + } + + return await sendRedirect(event, result.url, 303) +}) diff --git a/apps/blog-nuxt/server/api/auth/clerk/register.get.ts b/apps/blog-nuxt/server/api/auth/clerk/register.get.ts new file mode 100644 index 00000000..6c792c33 --- /dev/null +++ b/apps/blog-nuxt/server/api/auth/clerk/register.get.ts @@ -0,0 +1,5 @@ +import { registerWithClerk } from '@holo-js/auth-clerk' + +export default defineEventHandler(async (event) => { + return await registerWithClerk(event) +}) diff --git a/apps/blog-sveltekit/.env.example b/apps/blog-sveltekit/.env.example index d382e1b1..023507f7 100644 --- a/apps/blog-sveltekit/.env.example +++ b/apps/blog-sveltekit/.env.example @@ -48,9 +48,9 @@ WORKOS_REDIRECT_URI= WORKOS_SESSION_COOKIE= CLERK_PUBLISHABLE_KEY= CLERK_SECRET_KEY= -CLERK_JWT_KEY= CLERK_API_URL= CLERK_FRONTEND_API= +CLERK_REDIRECT_URI= CLERK_SESSION_COOKIE= BROADCAST_CONNECTION=holo diff --git a/apps/blog-sveltekit/config/auth.ts b/apps/blog-sveltekit/config/auth.ts index b54d336e..c1ec02f4 100644 --- a/apps/blog-sveltekit/config/auth.ts +++ b/apps/blog-sveltekit/config/auth.ts @@ -65,13 +65,14 @@ export default defineAuthConfig({ }, // Add a dedicated guard and provider if WorkOS users should resolve through a different model. clerk: { + provider: env('AUTH_CLERK_PROVIDER', 'app'), app: { publishableKey: env('CLERK_PUBLISHABLE_KEY'), secretKey: env('CLERK_SECRET_KEY'), - jwtKey: env('CLERK_JWT_KEY'), apiUrl: env('CLERK_API_URL'), frontendApi: env('CLERK_FRONTEND_API'), - sessionCookie: env('CLERK_SESSION_COOKIE', "__session"), + redirectUri: env('CLERK_REDIRECT_URI'), + sessionCookie: env('CLERK_SESSION_COOKIE', '__session'), }, }, // Add a dedicated guard and provider if Clerk users should resolve through a different model. diff --git a/apps/blog-sveltekit/src/routes/+layout.svelte b/apps/blog-sveltekit/src/routes/+layout.svelte index 87a94ab3..da96cef7 100644 --- a/apps/blog-sveltekit/src/routes/+layout.svelte +++ b/apps/blog-sveltekit/src/routes/+layout.svelte @@ -45,6 +45,9 @@
+
+ +
{:else} Login Register diff --git a/apps/blog-sveltekit/src/routes/api/auth/clerk/callback/+server.ts b/apps/blog-sveltekit/src/routes/api/auth/clerk/callback/+server.ts new file mode 100644 index 00000000..1d3e0542 --- /dev/null +++ b/apps/blog-sveltekit/src/routes/api/auth/clerk/callback/+server.ts @@ -0,0 +1,11 @@ +import { redirect, type RequestHandler } from '@sveltejs/kit' +import { completeClerkAuth } from '@holo-js/auth-clerk' + +export const GET = (async (event) => { + const result = await completeClerkAuth(event) + if (!result.ok) { + throw redirect(303, `/login?error=${encodeURIComponent(result.code)}`) + } + + throw redirect(303, '/admin') +}) satisfies RequestHandler diff --git a/apps/blog-sveltekit/src/routes/api/auth/clerk/login/+server.ts b/apps/blog-sveltekit/src/routes/api/auth/clerk/login/+server.ts new file mode 100644 index 00000000..19539798 --- /dev/null +++ b/apps/blog-sveltekit/src/routes/api/auth/clerk/login/+server.ts @@ -0,0 +1,6 @@ +import { loginWithClerk } from '@holo-js/auth-clerk' +import type { RequestHandler } from './$types' + +export const GET = (async (event) => { + return await loginWithClerk(event) +}) satisfies RequestHandler diff --git a/apps/blog-sveltekit/src/routes/api/auth/clerk/logout/+server.ts b/apps/blog-sveltekit/src/routes/api/auth/clerk/logout/+server.ts new file mode 100644 index 00000000..6bc08f9a --- /dev/null +++ b/apps/blog-sveltekit/src/routes/api/auth/clerk/logout/+server.ts @@ -0,0 +1,11 @@ +import { redirect, type RequestHandler } from '@sveltejs/kit' +import { logoutWithClerk } from '@holo-js/auth-clerk' + +export const POST = (async (event) => { + const result = await logoutWithClerk(event) + if (!result.ok) { + return Response.json(result, { status: 422 }) + } + + throw redirect(303, result.url) +}) satisfies RequestHandler diff --git a/apps/blog-sveltekit/src/routes/api/auth/clerk/register/+server.ts b/apps/blog-sveltekit/src/routes/api/auth/clerk/register/+server.ts new file mode 100644 index 00000000..341fe7ca --- /dev/null +++ b/apps/blog-sveltekit/src/routes/api/auth/clerk/register/+server.ts @@ -0,0 +1,6 @@ +import { registerWithClerk } from '@holo-js/auth-clerk' +import type { RequestHandler } from './$types' + +export const GET = (async (event) => { + return await registerWithClerk(event) +}) satisfies RequestHandler diff --git a/apps/blog-sveltekit/src/routes/login/+page.svelte b/apps/blog-sveltekit/src/routes/login/+page.svelte index 4a472483..0d10494b 100644 --- a/apps/blog-sveltekit/src/routes/login/+page.svelte +++ b/apps/blog-sveltekit/src/routes/login/+page.svelte @@ -31,6 +31,7 @@ Continue with Google Continue with GitHub Continue with WorkOS + Continue with Clerk
{ event.preventDefault(); form.submit() }}> diff --git a/apps/blog-sveltekit/src/routes/register/+page.svelte b/apps/blog-sveltekit/src/routes/register/+page.svelte index 2701da8d..34d93217 100644 --- a/apps/blog-sveltekit/src/routes/register/+page.svelte +++ b/apps/blog-sveltekit/src/routes/register/+page.svelte @@ -97,6 +97,7 @@ Already have an account? Register with WorkOS + Register with Clerk