Skip to main content

Overview

Polaris uses Clerk for authentication with GitHub OAuth support. This guide walks you through setting up Clerk and integrating it with Convex for secure, real-time user authentication.

Prerequisites

Setup Steps

1

Create a Clerk Application

  1. Go to the Clerk Dashboard
  2. Click Add Application
  3. Name your application (e.g., “Polaris”)
  4. Select GitHub as your social login provider
  5. Click Create Application
2

Configure Environment Variables

Copy your Clerk keys from the dashboard:
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
Never commit these keys to version control. Keep them in .env.local which should be in your .gitignore.
3

Set Up Clerk Provider

Polaris wraps the application with ClerkProvider and integrates it with Convex using ConvexProviderWithClerk:
src/components/providers.tsx
import { ClerkProvider, useAuth } from "@clerk/nextjs";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { ConvexReactClient } from "convex/react";

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

export const Providers = ({ children }: { children: React.ReactNode }) => {
  return (
    <ClerkProvider>
      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
        <Authenticated>
          {children}
        </Authenticated>
        <Unauthenticated>
          <UnauthenticatedView />
        </Unauthenticated>
        <AuthLoading>
          <AuthLoadingView />
        </AuthLoading>
      </ConvexProviderWithClerk>
    </ClerkProvider>
  );
};
This setup provides three authentication states:
  • Authenticated: User is signed in, show main app
  • Unauthenticated: User is not signed in, show login page
  • AuthLoading: Authentication status is being checked
4

Configure Convex Auth

Set the Clerk JWT issuer domain in your Convex deployment:
Terminal
npx convex env set CLERK_JWT_ISSUER_DOMAIN https://your-clerk-domain.clerk.accounts.dev
Your Clerk domain can be found in the Clerk Dashboard under API KeysJWT Issuer Domain.The Convex auth configuration automatically validates Clerk JWTs:
convex/auth.config.ts
import { AuthConfig } from "convex/server";

export default {
  providers: [
    {
      domain: process.env.CLERK_JWT_ISSUER_DOMAIN!,
      applicationID: "convex",
    },
  ],
} satisfies AuthConfig;

Authentication Flow

User Identity

Once authenticated, Convex queries and mutations can access the user’s identity:
convex/auth.ts
export const verifyAuth = async (ctx: QueryCtx | MutationCtx) => {
  const identity = await ctx.auth.getUserIdentity();

  if (!identity) {
    throw new Error("Unauthorized");
  }

  return identity;
};
This helper is used throughout the Convex backend to ensure only authenticated users can access their data:
convex/projects.ts
export const create = mutation({
  args: { name: v.string() },
  handler: async (ctx, args) => {
    const identity = await verifyAuth(ctx);

    const projectId = await ctx.db.insert("projects", {
      name: args.name,
      ownerId: identity.subject, // Clerk user ID
      updatedAt: Date.now(),
    });

    return projectId;
  },
});

Protected Routes

All routes are protected by default through the Providers component. Users must sign in with GitHub before accessing any part of the application.

Testing Authentication

1

Start the Development Server

Terminal
npm run dev
2

Visit the Application

Navigate to http://localhost:3000
3

Sign In with GitHub

Click Sign in with GitHub and authorize the application
4

Verify Access

After successful authentication, you should see the Polaris dashboard

Environment Variables Reference

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
string
required
Your Clerk publishable key (starts with pk_test_ or pk_live_)
CLERK_SECRET_KEY
string
required
Your Clerk secret key (starts with sk_test_ or sk_live_)
CLERK_JWT_ISSUER_DOMAIN
string
required
Your Clerk JWT issuer domain (set in Convex, not .env.local)

Troubleshooting

”Unauthorized” Error

If you see unauthorized errors in Convex functions:
  1. Verify CLERK_JWT_ISSUER_DOMAIN is set correctly in Convex:
    npx convex env get CLERK_JWT_ISSUER_DOMAIN
    
  2. Check that your Clerk keys are valid and match your environment (test vs. production)
  3. Ensure the Clerk application has GitHub OAuth enabled

Redirect Loop

If you experience a redirect loop:
  1. Clear your browser cookies for localhost
  2. Verify your Clerk domain settings in the dashboard
  3. Check that NEXT_PUBLIC_CONVEX_URL is set correctly

Next Steps

Build docs developers (and LLMs) love