<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Satoshi</title>
    <description>The latest articles on DEV Community by Satoshi (@satoshi_9a44c57cd2e96fbff).</description>
    <link>https://dev.to/satoshi_9a44c57cd2e96fbff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2965960%2F05b17115-6959-45ea-9c52-0af12edf9ea8.png</url>
      <title>DEV Community: Satoshi</title>
      <link>https://dev.to/satoshi_9a44c57cd2e96fbff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/satoshi_9a44c57cd2e96fbff"/>
    <language>en</language>
    <item>
      <title>Setting Up Clerk Authentication with NestJS and Next.js</title>
      <dc:creator>Satoshi</dc:creator>
      <pubDate>Sun, 13 Jul 2025 19:40:21 +0000</pubDate>
      <link>https://dev.to/satoshi_9a44c57cd2e96fbff/setting-up-clerk-authentication-with-nestjs-and-nextjs-3nai</link>
      <guid>https://dev.to/satoshi_9a44c57cd2e96fbff/setting-up-clerk-authentication-with-nestjs-and-nextjs-3nai</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1d18z0ah96mt1ihiqyhj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1d18z0ah96mt1ihiqyhj.webp" alt=" " width="703" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modern web apps need secure, scalable, and developer-friendly authentication. Clerk offers a full-stack authentication solution that works great with Next.js (frontend) and can be securely integrated with a NestJS (backend) server.&lt;/p&gt;

&lt;p&gt;In this article, we’ll walk through how to set up Clerk authentication in a fullstack app using Next.js for the UI and NestJS for protected backend APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔐 What is Clerk?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; is the most comprehensive User Management Platform.&lt;/p&gt;

&lt;p&gt;Clerk provides plug-and-play authentication components for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign in / Sign up flows&lt;/li&gt;
&lt;li&gt;User profile management&lt;/li&gt;
&lt;li&gt;Session handling&lt;/li&gt;
&lt;li&gt;OAuth and email/password login&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It integrates easily into React/Next.js apps and supports token-based API protection for backend services.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Overview of the Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnewfqgcg9n43q8zvxkne.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnewfqgcg9n43q8zvxkne.webp" alt=" " width="720" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Setup in Next.js (Frontend)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install Clerk SDK&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;pnpm add @clerk/nextjs&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add clerkMiddleware() to your app&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;clerkMiddleware() grants you access to user authentication state throughout your app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a middleware.ts file.&lt;br&gt;
If you’re using the /src directory, create middleware.ts in the /src directory, if not in the root directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your middleware.ts file, export the clerkMiddleware() helper:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware()

export const config = {
  matcher: [
    // Skip Next.js internals and all static files, unless found in search params
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add  and Clerk components to your app
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Metadata } from 'next'
import {
  ClerkProvider,
  SignInButton,
  SignUpButton,
  SignedIn,
  SignedOut,
  UserButton,
} from '@clerk/nextjs'
import { Geist, Geist_Mono } from 'next/font/google'
import './globals.css'

const geistSans = Geist({
  variable: '--font-geist-sans',
  subsets: ['latin'],
})

const geistMono = Geist_Mono({
  variable: '--font-geist-mono',
  subsets: ['latin'],
})

export const metadata: Metadata = {
  title: 'Clerk Next.js Quickstart',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: Readonly&amp;lt;{
  children: React.ReactNode
}&amp;gt;) {
  return (
    &amp;lt;ClerkProvider
      appearance={{
        cssLayerName: 'clerk',
      }}
    &amp;gt;
      &amp;lt;html lang="en"&amp;gt;
        &amp;lt;body className={`${geistSans.variable} ${geistMono.variable} antialiased`}&amp;gt;
          &amp;lt;header className="flex justify-end items-center p-4 gap-4 h-16"&amp;gt;
            &amp;lt;SignedOut&amp;gt;
              &amp;lt;SignInButton /&amp;gt;
              &amp;lt;SignUpButton&amp;gt;
                &amp;lt;button className="bg-[#6c47ff] text-white rounded-full font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 cursor-pointer"&amp;gt;
                  Sign Up
                &amp;lt;/button&amp;gt;
              &amp;lt;/SignUpButton&amp;gt;
            &amp;lt;/SignedOut&amp;gt;
            &amp;lt;SignedIn&amp;gt;
              &amp;lt;UserButton /&amp;gt;
            &amp;lt;/SignedIn&amp;gt;
          &amp;lt;/header&amp;gt;
          {children}
        &amp;lt;/body&amp;gt;
      &amp;lt;/html&amp;gt;
    &amp;lt;/ClerkProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Get JWT for Backend and call backend API endpoint
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { getToken } = useAuth();
const token = await getToken();
await fetch('/api/protected', {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚙️ Setup in NestJS (Backend)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install Dependency&lt;br&gt;
&lt;code&gt;pnpm add @clerk/backend&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Clerk Provider&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;./src/providers/clerk.provider.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createClerkClient } from '@clerk/backend';
import { ConfigService } from '@nestjs/config';

export const ClerkClientProvider = {
  provide: 'ClerkClient',
  useFactory: (configService: ConfigService) =&amp;gt; {
    return createClerkClient({
      publishableKey: configService.get('CLERK_PUBLISHABLE_KEY'),
      secretKey: configService.get('CLERK_SECRET_KEY'),
    });
  },
  inject: [ConfigService],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;AuthGuard&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;./src/auth-guard/auth-guard.module.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { AuthGuardService } from './auth-guard.service';
import { ClerkClientProvider } from 'src/providers/clerk-client.provider';

@Module({
  providers: [
    AuthGuardService,
    ClerkClientProvider
  ],
  exports: ['ClerkClient'],
})
export class AuthGuardModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;./src/auth-guard/auth-guard.service.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
  Inject,
} from '@nestjs/common';
import { Request } from 'express';
import { ClerkClient, verifyToken } from '@clerk/backend';

@Injectable()
export class AuthGuardService implements CanActivate {
  constructor(
    @Inject('ClerkClient')
    private readonly clerkClient: ClerkClient,
  ) {}

  async canActivate(context: ExecutionContext): Promise&amp;lt;boolean&amp;gt; {
    const request = context.switchToHttp().getRequest&amp;lt;Request&amp;gt;();

    // Check for session cookie
    const sessionToken = request.cookies.__session;

    // Check for bearer token
    const authHeader = request.headers.authorization;
    const bearerToken = authHeader?.startsWith('Bearer ')
      ? authHeader.substring(7)
      : null;

    if (!sessionToken &amp;amp;&amp;amp; !bearerToken) {
      throw new UnauthorizedException('No authentication token provided');
    }

    try {
      // Try to verify the token (either session or bearer)
      const tokenToVerify = bearerToken || sessionToken;
      const tokenPayload = await verifyToken(tokenToVerify, {
        secretKey: process.env.CLERK_SECRET_KEY,
      });

      if (!tokenPayload) {
        throw new UnauthorizedException('Invalid session');
      }

      const user = await this.clerkClient.users.getUser(tokenPayload.sub);
      (request as any).user = user;
      return true;
    } catch (err) {
      console.error('Token verification error:', err);
      throw new UnauthorizedException('Invalid or expired token');
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Protect API Routes Using the AuthGuard
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Controller, Get, UseGuards, Req } from '@nestjs/common';
import { AuthGuardService } from './auth/auth.guard';

@Controller('api')
export class ExampleController {
  @UseGuards(AuthGuardService)
  @Get('profile')
  getProfile(@Req() req) {
    return req.user;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Clerk + Next.js + NestJS is a powerful trio for building modern, secure, and scalable fullstack applications.&lt;/p&gt;

&lt;p&gt;With Clerk, developers benefit from prebuilt UI components, robust session management, and built-in support for OAuth, email/password, and multi-factor authentication. On the frontend, Next.js offers seamless integration with Clerk’s SDK, allowing you to quickly build and protect pages using ClerkProvider and Clerk hooks.&lt;/p&gt;

&lt;p&gt;Meanwhile, on the backend, NestJS gives you a modular, testable framework to handle protected routes. By using a custom AuthGuard that verifies JWTs or session cookies issued by Clerk, you can securely validate user identity, enforce authorization rules, and maintain a clean separation of concerns.&lt;/p&gt;

&lt;p&gt;Whether you’re building a SaaS platform, an internal admin tool, or a consumer app, this stack helps you ship faster while staying secure.&lt;/p&gt;

&lt;p&gt;If you need deeper integration examples, RBAC patterns, SSR protection, or a visual diagram of the full auth flow — feel free to reach out or check the next article!&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>nestjs</category>
      <category>clerk</category>
    </item>
  </channel>
</rss>
