Prerequisite You should already have a Next.js app created.
Step 1. Install Protocol Auth in your NextjS app:
Once created, you will see environment variables for your project on the dashboard.
Step 3. Add the environment variables to your .env
file:
Step 4. Project setup (app router)
Add the following code to lib/auth.ts:
import { auth } from "@protoxyz/auth";
import { redirect } from "next/navigation";
interface ProtectOptions {
role?: string;
orgRole?: string;
}
export const protectPage = async (options?: ProtectOptions) => {
const session = await auth();
if (!session) {
return redirect(getLoginUrl());
}
if (options?.role && session.claims?.role !== options.role) {
return redirect("/unauthorized");
}
return session;
};
export const getAccountsUrl = ({ path = "/" }: { path?: string } = {}) => {
return new URL(path, `https://${process.env.NEXT_PUBLIC_PXYZ_DOMAIN}`);
};
export const getLoginUrl = (redirectPath: string | undefined = "/") => {
const url = getAccountsUrl({ path: "/sign-in" });
const redirectUri = new URL("/api/auth/callback", getWebUrl());
redirectUri.searchParams.set("redirectPath", redirectPath);
url.searchParams.set("redirectUri", redirectUri.toString());
return url.toString();
};
export const getSignupUrl = (redirectPath: string | undefined = "/onboard") => {
const url = getAccountsUrl({ path: "/sign-up" });
const redirectUri = new URL("/api/auth/callback", getWebUrl());
redirectUri.searchParams.set("redirectPath", redirectPath);
url.searchParams.set("redirectUri", redirectUri.toString());
return url.toString();
};
export function getWebUrl() {
return process.env.NODE_ENV === "production"
? `https://www.yourdomain.com`
: "http://localhost:3000";
}
Whenever you need to determine whether or not a user is authenticated, you can use the auth
function. If the user is not authenticated, the function will return null
. If the user is authenticated, the function will return the verified JWT object.
Add an api route to handle the callback from the hosted accounts page. Create a new file called app/api/auth/callback.ts
. Add the following code:
import type { NextRequest } from "next/server";
import { handleCallback } from "@protoxyz/auth";
export const GET = async (req: NextRequest) => {
return await handleCallback(req, async ({ req, res, session }) => {
console.log("Auth was successful!!!", session);
return res;
});
};
Step 5. Protect pages (app router)
Create a new page in your project that you want to secure. For example, create a new file called app/onboard/page.tsx
. Add the following code:
import { protectPage } from "@/lib/auth";
export default function OnboardPage() {
const session = protectPage();
return (
<div>
Welcome to the onboarding page! Only logged in users can see this.
</div>
);
}
Step 6. Protect api routes (app router)
Create a new file called app/api/protected/route.ts
. Add the following code:
import { auth } from "@/lib/auth";
import { NextApiRequest, NextApiResponse } from "next";
export default async function GET(req: NextApiRequest) {
const session = await auth();
if (!session) {
return res.json({ error: "Unauthorized" });
}
return res.json({ message: "Hello, secret message!" });
}
Step 7. Protecting server actions
You can also protect server actions by calling the auth
function. For example, if your actions are in lib/actions.ts add the following code:
"use server";
import "server-only";
import { auth } from "@/lib/auth";
export async function createTask(formData: FormData) {
const session = await auth();
if (!session) {
return new Response("Unauthorized", { status: 401 });
}
}
Step 8. Checking if a user is authenticated in middleware
You can also check if a user is authenticated in middleware. For example, if you want to check if a user is authenticated in a middleware, add the following code:
import { auth } from "@/lib/auth";
export default function middleware(req: NextRequest) {
const session = await auth();
if (!session) {
return new Response("Unauthorized", { status: 401 });
}
return NextResponse.next();
}
If you only need to check if a user is authenticated, you can use the getToken
function. For example:
import { getToken } from "@protoxyz/auth";
export default function middleware(req: NextRequest) {
const token = getToken(req);
if (!token) {
return new Response("No token found, user is not logged in", {
status: 401,
});
}
return NextResponse.next();
}
Step 9. Passing user data to client components
You can easily pass user data to client components from the server. For example, create a new component in components/user-button.tsx
. Add the following code:
import type { UserSession } from "@protoxyz/auth";
export default function UserButton({ user }: { user: UserSession["claims"] }) {
return (
<button>
{user.name} - {user.email}
</button>
);
}
And then call it from your protected page:
import { protectPage } from "@/lib/auth";
import UserButton from "@/components/user-button";
export default function OnboardPage() {
const session = protectPage();
return (
<div>
<UserButton user={session.claims} />
</div>
);
}