Back to list
JanSzewczyk

clerk-auth-proxy

by JanSzewczyk

This is Next.js Szumplate, an open source template for enterprise projects! It is packed with features that will help you create an efficient, maintainable and enjoyable application.

1🍴 0📅 Jan 18, 2026

SKILL.md


name: clerk-auth-proxy version: 1.0.0 lastUpdated: 2026-01-18 description: Implement Clerk authentication with Next.js 16 proxy pattern, session claims, onboarding gates, and user metadata management. Use when working with authentication, authorization, or user session management. tags: [clerk, authentication, next.js, proxy, session-claims, onboarding] author: Szum Tech Team allowed-tools: Read, Write, Edit, Glob, Grep, Bash, mcp__context7__resolve-library-id, mcp__context7__get-library-docs context: fork agent: general-purpose user-invocable: true examples:

  • Add authentication check to a server action
  • Implement onboarding gate for new users
  • Update user metadata after completing a flow
  • Create protected route with role-based access

Clerk Authentication & Proxy Skill

Implement Clerk authentication in Next.js 16 using the proxy pattern (not middleware!), manage session claims, and handle user metadata.

Reference Files:

Critical: Next.js 16 Uses Proxy, NOT Middleware

IMPORTANT: Next.js 16 introduced the proxy pattern which replaces the traditional middleware.ts for Clerk.

Next.js VersionFile NameRuntime
15 and earliermiddleware.tsEdge Runtime
16+proxy.tsNode.js Runtime

The proxy pattern provides:

  • Full Node.js runtime (not Edge limitations)
  • Better async/await support
  • Access to all Node.js APIs
  • Improved performance

Quick Start

1. Authentication Check in Server Actions

"use server";

import { auth } from "@clerk/nextjs/server";
import type { ActionResponse } from "~/lib/action-types";

export async function myAction(data: InputType): ActionResponse<OutputType> {
  // 1. Always check authentication first
  const { userId } = await auth();
  if (!userId) {
    return { success: false, error: "Authentication required" };
  }

  // 2. Your business logic here
  // ...
}

2. Authentication Check in Page Loaders

import { auth } from "@clerk/nextjs/server";
import { redirect, unauthorized } from "next/navigation";

async function loadData() {
  const { userId, isAuthenticated, sessionClaims } = await auth();

  if (!isAuthenticated) {
    return unauthorized();
  }

  // Check custom session claims
  if (sessionClaims?.metadata.onboardingComplete !== true) {
    redirect("/onboarding");
  }

  // Load user data...
}

3. Updating User Metadata

import { clerkClient } from "@clerk/nextjs/server";

const client = await clerkClient();
await client.users.updateUser(userId, {
  publicMetadata: {
    onboardingComplete: true,
    role: "user"
  }
});

Key Concepts

Authentication Object

The auth() function returns:

interface AuthObject {
  userId: string | null;           // Clerk user ID
  isAuthenticated: boolean;        // Is user logged in
  sessionClaims: CustomJwtSessionClaims | null;  // Custom claims
  redirectToSignIn: (opts?) => Response;  // Redirect helper
}

Session Claims Type Definition

Define custom claims in types/clerk.d.ts:

export {};

declare global {
  interface CustomJwtSessionClaims {
    metadata: {
      onboardingComplete?: boolean;
      role?: "user" | "admin";
    };
  }
}

Public vs Private Metadata

TypeVisibilityUse Case
publicMetadataIncluded in session token, readable on clientOnboarding status, roles, preferences
privateMetadataServer-only, never sent to clientInternal flags, sensitive data
unsafeMetadataUser-editable via Clerk componentsProfile preferences, settings

File Locations

PurposeFile
Proxy configurationproxy.ts (root)
Session claims typestypes/clerk.d.ts
Auth helpersfeatures/auth/server/db/user.ts
Providers setupcomponents/providers.tsx

Common Patterns

Protected Server Action

"use server";

import { auth } from "@clerk/nextjs/server";

export async function protectedAction(): ActionResponse {
  const { userId, isAuthenticated } = await auth();

  if (!isAuthenticated || !userId) {
    return { success: false, error: "Unauthorized" };
  }

  // Action logic...
}

Protected Page with Redirect

import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";

export default async function ProtectedPage() {
  const { userId } = await auth();

  if (!userId) {
    redirect("/sign-in");
  }

  // Page content...
}

Onboarding Gate Pattern

See onboarding-gate.md for complete implementation.

Security Checklist

When implementing authentication:

  1. Always verify userId - Never trust client-provided user IDs
  2. Check authorization - Verify user owns the resource they're accessing
  3. Use server-only - Mark auth modules with server-only package
  4. Log auth events - Log authentication failures for security monitoring
  5. Handle edge cases - Expired sessions, revoked tokens

Running and Testing

# Type check
npm run type-check

# Run auth-related tests
npm run test -- features/auth

# E2E tests with authentication
npm run test:e2e
  • server-actions - For implementing server actions with auth checks
  • firebase-firestore - For database operations after authentication

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon