Skip to content
GitHub

Auth Providers

Replace Orion Kit’s custom JWT authentication with popular auth providers for enterprise features, social login, and SSO.

Orion Kit’s custom JWT system is perfect for most SaaS apps, but you might need auth providers for:

  • Enterprise SSO - SAML, OIDC, Active Directory
  • Social Login - Google, GitHub, Apple, Microsoft
  • Advanced Security - MFA, device management, audit logs
  • Compliance - SOC2, GDPR, HIPAA requirements
  • Team Management - Organizations, roles, permissions
ProviderBest ForFree TierPricingDifficulty
ClerkModern apps, great DX10k MAU$25/mo⭐⭐⭐
Auth0Enterprise, compliance7k MAU$23/mo⭐⭐⭐⭐
Better AuthOpen source, self-hostedUnlimitedFree⭐⭐⭐
Supabase AuthDatabase-first apps50k MAU$25/mo⭐⭐
NextAuth.jsCustom, flexibleUnlimitedFree⭐⭐⭐⭐

Best for: Modern SaaS apps with great developer experience.

pnpm add @clerk/nextjs

Environment:

# apps/app/.env.local
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...

# apps/api/.env.local
CLERK_SECRET_KEY=sk_test_...

apps/app/app/layout.tsx:

import { ClerkProvider } from "@clerk/nextjs";

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

apps/app/middleware.ts:

import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware({
  publicRoutes: ["/", "/sign-in", "/sign-up"],
  ignoredRoutes: ["/api/webhooks/stripe"],
});

export const config = {
  matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};

apps/api/app/auth/me/route.ts:

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

export async function GET() {
  const { userId } = auth();

  if (!userId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  // Get user from Clerk
  const user = await clerkClient.users.getUser(userId);

  return NextResponse.json({
    success: true,
    data: {
      id: user.id,
      email: user.emailAddresses[0]?.emailAddress,
      name: user.fullName,
      image: user.imageUrl,
    },
  });
}

apps/app/hooks/use-auth.ts:

import { useUser, useAuth } from "@clerk/nextjs";

export function useAuth() {
  const { user, isLoaded } = useUser();
  const { signOut } = useAuth();

  return {
    user: user
      ? {
          id: user.id,
          email: user.emailAddresses[0]?.emailAddress,
          name: user.fullName,
          image: user.imageUrl,
        }
      : null,
    isLoading: !isLoaded,
    signOut,
  };
}

Best for: Open source, self-hosted, full control.

pnpm add better-auth

packages/auth/src/better-auth.ts:

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@workspace/database";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "pg",
  }),
  emailAndPassword: {
    enabled: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
  },
});

apps/api/app/auth/[...all]/route.ts:

import { auth } from "@workspace/auth/better-auth";

export const { GET, POST } = auth.handler;

packages/auth/src/better-auth-client.ts:

import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
});

export const { signIn, signUp, signOut, useSession } = authClient;

Run both auth systems in parallel during migration:

// Support both auth methods
export async function getCurrentUser(req: Request) {
  // Try Clerk first
  const clerkUser = await getClerkUser(req);
  if (clerkUser) return clerkUser;

  // Fallback to custom JWT
  const jwtUser = await getJWTUser(req);
  return jwtUser;
}

Create migration script to move existing users:

// packages/auth/src/migrate-users.ts
export async function migrateUsersToClerk() {
  const users = await db.select().from(users);

  for (const user of users) {
    await clerkClient.users.createUser({
      emailAddress: [user.email],
      firstName: user.name?.split(" ")[0],
      lastName: user.name?.split(" ")[1],
    });
  }
}

Replace auth hooks gradually:

// Before: Custom JWT
const { data: user } = useAuth();

// After: Clerk
const { user } = useUser();

Most auth providers handle user storage, so you can simplify your schema:

// Before: Custom user table
export const users = pgTable("users", {
  id: uuid("id").primaryKey().defaultRandom(),
  email: varchar("email", { length: 255 }).notNull().unique(),
  password: varchar("password", { length: 255 }).notNull(),
  name: varchar("name", { length: 255 }),
  // ... other fields
});

// After: Minimal user table (if needed)
export const userProfiles = pgTable("user_profiles", {
  id: uuid("id").primaryKey(), // Matches auth provider ID
  subscriptionId: varchar("subscription_id"),
  preferences: jsonb("preferences"),
  // ... app-specific fields only
});
  • Enterprise customers need SSO
  • Social login is a must-have feature
  • Compliance requirements (SOC2, GDPR)
  • Team/organization features needed
  • Advanced security (MFA, device management)
  • Audit logs required
  • Simple SaaS with email/password only
  • Cost is a concern (auth providers cost $25+/mo)
  • Full control over user data needed
  • Custom flows required
  • MVP stage - don’t over-engineer
SolutionFree TierPaid PlansMonthly Cost
Custom JWTUnlimited$0$0
Clerk10k MAU$25/mo$0-25
Auth07k MAU$23/mo$0-23
Better AuthUnlimitedFree$0
Supabase50k MAU$25/mo$0-25
  1. Start with custom JWT - It’s free and works for most cases
  2. Switch when needed - Don’t over-engineer from day one
  3. Plan migration - Keep both systems during transition
  4. Test thoroughly - Auth changes affect everything
  5. Update documentation - Help your team understand the new flow
  • Choose auth provider based on requirements
  • Set up development environment
  • Create migration plan for existing users
  • Update API routes to use new auth
  • Update frontend components
  • Test all authentication flows
  • Update environment variables
  • Deploy to staging first
  • Monitor for issues
  • Remove old auth code

Clerk docs · Auth0 docs · Better Auth docs