Authentication built natively for Next.js App Router — simple, cookie-first, and developer-first.
MyAuth is a backend-first authentication system designed specifically for Next.js App Router. It gives you control over sessions and tokens without the magic or vendor lock-in of other auth providers.
- Hidden token handling that breaks in production
- Vendor lock-in that makes migration painful
- Heavy UI components that don't match your design
- abstracted sessions that are hard to debug
- HTTP-only cookies — Sessions stored securely in httpOnly cookies, never in localStorage
- Server-first — Auth logic lives on the server, not in your client bundle
- Predictable — No magic. What you see is what runs in production
- Self-hostable — Your auth, your infrastructure
- Cookie-based sessions — Secure, httpOnly, CSRF-safe
- JWT access tokens — Short-lived, signed with RS256
- Refresh token rotation — Automatic token refresh with secure rotation
- OAuth providers — Google, GitHub (more coming)
- Email OTP — Passwordless login via one-time codes
- Route protection — Edge-compatible middleware
- Server helpers —
auth(),currentUser(),requireAuth()in Server Components - Client hooks —
useAuth(),useUser()for React components
npx create-next-app@latest my-app
cd my-appnpm install @myauth/next- Sign up at myauth.com
- Create an application in the dashboard
- Copy your
CLIENT_IDandCLIENT_SECRET
# .env.local
# Public (safe for browser)
NEXT_PUBLIC_CLIENT_ID=your_client_id
# Server-only (never expose to client)
CLIENT_SECRET=your_client_secretCreate middleware.ts in your project root:
import { withAuthMiddleware } from "@myauth/next";
export default withAuthMiddleware({
clientId: process.env.NEXT_PUBLIC_CLIENT_ID!,
});
export const config = {
matcher: ["/dashboard/:path*"],
};Wrap your app in app/layout.tsx:
import { AuthProvider } from "@myauth/next";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<AuthProvider clientId={process.env.NEXT_PUBLIC_CLIENT_ID!}>
{children}
</AuthProvider>
</body>
</html>
);
}Create app/callback/page.tsx:
import { AuthenticateWithRedirectCallback } from "@myauth/next";
export default function CallbackPage() {
return <AuthenticateWithRedirectCallback />;
}Create app/api/auth/token/route.ts:
import { createAuthCallbackHandler } from "@myauth/next";
export const POST = createAuthCallbackHandler({
clientId: process.env.CLIENT_SECRET!, // Note: use CLIENT_ID here
clientSecret: process.env.CLIENT_SECRET!,
});import { auth } from "@myauth/next";
export default async function Dashboard() {
const session = await auth();
if (!session) {
return <div>Please log in</div>;
}
return <div>Welcome, {session.user.email}!</div>;
}import { useAuth } from "@myauth/next";
export default function Header() {
const { user, loading, logout } = useAuth();
if (loading) return <div>Loading...</div>;
return (
<header>
{user ? (
<>
<span>Welcome, {user.email}</span>
<button onClick={logout}>Logout</button>
</>
) : (
<a href="/login">Login</a>
)}
</header>
);
}export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*", "/api/protected/:path*"],
};| Function | Description |
|---|---|
auth() |
Get current session in Server Components |
currentUser() |
Get current user with full profile |
requireAuth() |
Get session or throw error |
| Hook | Description |
|---|---|
useAuth() |
Access user, loading state, login/logout functions |
useUser() |
Shorthand for user object with loading state |
| Function | Description |
|---|---|
withAuthMiddleware(options) |
Protect routes with route matching |
| Component | Description |
|---|---|
AuthProvider |
React context for auth state |
AuthenticateWithRedirectCallback |
Handle OAuth callback |
- HTTP-only cookies — Refresh tokens never exposed to JavaScript
- CSRF protection — OAuth state parameter prevents cross-site attacks
- Token rotation — Each refresh generates new token pair
- Short-lived access tokens — 15 minute expiry by default
- Secure signing — RS256 JWTs with per-app signing keys
Choose MyAuth if:
- You're using Next.js App Router
- You care about auth correctness
- You want control over sessions & tokens
- You prefer server-side auth over client-side magic
- You want to avoid vendor lock-in
Choose a different solution if:
- You need auth in 10 minutes flat
- You want pre-built UI components
- You don't care about implementation details
| MyAuth | Clerk | Auth0 | |
|---|---|---|---|
| Framework focus | Next.js App Router | Multi-framework | Multi-framework |
| UI components | Minimal | Heavy | None |
| Token model | JWT, you control | Abstracted | Abstracted |
| Self-hostable | Yes | No | Enterprise only |
| Vendor lock-in | Low | High | Medium |
| Pricing | Free tier | Paid at scale | Enterprise |
- GitHub Issues: https://github.com/myauth/myauth/issues
- Discord: https://discord.gg/myauth
MIT