We use tracking cookies to understand how you use the product and help us improve it. For more information on how we store cookies, read our  privacy policy.

Setup & Configuration

Configure Clerk authentication with environment variables, middleware protection, and custom sign-in flows

Complete guide to setting up Clerk authentication in Plainform, from API keys to middleware configuration.

Prerequisites

Before setting up Clerk, ensure you have:

  • A Plainform project installed and running
  • Node.js 18+ installed
  • A Clerk account (free tier available)

Clerk is already installed in Plainform (@clerk/nextjs v6.38+). You only need to configure environment variables.

Quick Setup

Create Clerk Application

  1. Sign up at clerk.com
  2. Click "Add application"
  3. Name your application (e.g., "Plainform App")
  4. Select "Next.js" as your framework
  5. Click "Create application"

Get API Keys

In your Clerk Dashboard:

  1. Navigate to API Keys in the sidebar
  2. You'll see two keys:
    • Publishable Key (starts with pk_test_ or pk_live_)
    • Secret Key (starts with sk_test_ or sk_live_)
  3. Keep this page open - you'll need these keys in the next step

Never commit your Secret Key to version control. It should only be in .env files.

Configure Environment Variables

Add these variables to your .env file in the project root:

Env VariableTypeDefault
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
string
pk_test_xxxx
CLERK_SECRET_KEY
string
sk_test_xxxx
NEXT_PUBLIC_CLERK_SIGN_IN_URL
string
/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL
string
/sign-up

Example .env file:

.env
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_xxxxxxxxxxxxxxxxxxxx"
CLERK_SECRET_KEY="sk_test_xxxxxxxxxxxxxxxxxxxx"
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"

These variables are validated on startup by env.ts. The app won't start if any required variable is missing or invalid.

Verify Setup

Start your development server:

Start dev server
npm run dev

If configuration is correct, you'll see:

  • No validation errors in the terminal
  • The app starts successfully on http://localhost:3000

If you see errors, double-check:

  • Variable names match exactly (case-sensitive)
  • Keys are copied correctly from Clerk Dashboard
  • .env file is in the project root

Test Authentication

  1. Navigate to http://localhost:3000/sign-up
  2. Create a test account
  3. You should be redirected to the home page
  4. Check the Clerk Dashboard → Users to see your new user

Middleware Configuration

Plainform includes pre-configured middleware to protect routes. The configuration is in middleware.ts:

middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

// Define public routes (accessible without authentication)
const isPublicRoute = createRouteMatcher([
  '/',
  '/sign-in(.*)',
  '/sign-up(.*)',
  '/forgot-password(.*)',
  '/sso-callback(.*)',
  '/blog(.*)',
  '/docs(.*)',
  '/api/webhooks(.*)',
]);

export default clerkMiddleware(async (auth, req) => {
  // Protect all routes except public ones
  if (!isPublicRoute(req)) {
    await auth.protect();
  }
});

export const config = {
  matcher: [
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    '/(api|trpc)(.*)',
  ],
};

Customizing Protected Routes

To add or remove protected routes, modify the isPublicRoute matcher:

Add public route
const isPublicRoute = createRouteMatcher([
  '/',
  '/sign-in(.*)',
  '/sign-up(.*)',
  '/pricing',        // Add this
  '/about',          // Add this
  '/blog(.*)',
  '/docs(.*)',
]);

To protect specific routes with additional checks:

Role-based protection
const isAdminRoute = createRouteMatcher(['/admin(.*)']);

export default clerkMiddleware(async (auth, req) => {
  if (!isPublicRoute(req)) {
    await auth.protect();
  }
  
  // Additional check for admin routes
  if (isAdminRoute(req)) {
    await auth.protect((has) => {
      return has({ role: 'admin' });
    });
  }
});

Provider Setup

Clerk is initialized in the root layout via ClerkProvider. This is already configured in Plainform:

app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';

export default function RootLayout({ children }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

The provider wraps your entire app, making Clerk hooks available everywhere.

Sign-In/Sign-Up Pages

Plainform includes custom sign-in and sign-up pages at:

  • app/(auth)/sign-in/[[...sign-in]]/page.tsx
  • app/(auth)/sign-up/[[...sign-up]]/page.tsx

These pages use custom forms built with Clerk's useSignIn and useSignUp hooks, not Clerk's pre-built components:

app/(auth)/sign-in/[[...sign-in]]/page.tsx
import { SignInForm } from '@/components/user/SignInForm';

export default function SignInPage() {
  return <SignInForm />;
}

The custom forms (SignInForm and SignUpForm) are located in components/user/ and provide:

  • Custom styling that matches Plainform's design system
  • OAuth integration (Google, GitHub)
  • Email/password authentication
  • Form validation with Zod and React Hook Form
  • Error handling with toast notifications

Custom Form Implementation

The forms use Clerk's authentication hooks directly:

components/user/SignInForm.tsx (simplified)
'use client';

import { useSignIn } from '@clerk/nextjs';
import { useForm } from 'react-hook-form';

export function SignInForm() {
  const { signIn, setActive } = useSignIn();
  const { register, handleSubmit } = useForm();

  const onSubmit = async (data) => {
    const signInAttempt = await signIn.create({
      identifier: data.identifier,
      password: data.password,
    });
    
    if (signInAttempt.status === 'complete') {
      await setActive({ session: signInAttempt.createdSessionId });
      router.push('/');
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Custom form fields */}
    </form>
  );
}

This approach gives you full control over the UI while leveraging Clerk's authentication logic.

OAuth Providers

Plainform's custom forms include OAuth integration for Google and GitHub. To enable OAuth providers:

Enable in Clerk Dashboard

  1. Go to Clerk Dashboard → User & Authentication → Social Connections
  2. Toggle on desired providers (Google, GitHub, Microsoft, etc.)
  3. Follow provider-specific setup instructions
  4. Save changes

OAuth in Custom Forms

The custom forms (SignInForm and SignUpForm) include OAuth buttons using the OAuthConnection component:

OAuth integration in custom forms
import { OAuthConnection } from '@/components/user/OAuthConnection';

<OAuthConnection strategy="oauth_google" icon="Google">
  Continue with Google
</OAuthConnection>

<OAuthConnection strategy="oauth_github" icon="Github">
  Continue with GitHub
</OAuthConnection>

Once enabled in the Clerk Dashboard, these buttons will work automatically.

Test OAuth Flow

  1. Navigate to /sign-in
  2. Click an OAuth provider button (Google or GitHub)
  3. Complete OAuth flow
  4. You'll be redirected back to your app

OAuth providers require additional configuration (OAuth client IDs, secrets) in the Clerk Dashboard. Follow Clerk's provider-specific guides.

Development vs Production

Development Setup:

  • Use test keys (pk_test_, sk_test_)
  • Test mode in Clerk Dashboard
  • No real emails sent (use Clerk's test email feature)
  • Webhooks can use Clerk's webhook testing tool

Testing:

Test with Clerk CLI
npx @clerk/cli webhooks listen --forward-to http://localhost:3000/api/webhooks/clerk

Production Setup:

  • Use live keys (pk_live_, sk_live_)
  • Production mode in Clerk Dashboard
  • Real emails sent to users
  • Configure production webhook endpoints

Environment Variables: Set these in your hosting platform (Vercel, etc.):

  • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY (live key)
  • CLERK_SECRET_KEY (live key)
  • NEXT_PUBLIC_CLERK_SIGN_IN_URL
  • NEXT_PUBLIC_CLERK_SIGN_UP_URL

Verification

After setup, verify everything works:

  1. Sign Up Flow: Create a new account at /sign-up
  2. Sign In Flow: Sign in at /sign-in
  3. Protected Routes: Try accessing a protected page without auth
  4. User Data: Check Clerk Dashboard → Users for new accounts
  5. Middleware: Verify public routes are accessible, protected routes require auth

Next Steps

How is this guide ?

Last updated on