Monocloud auth nextjs
Skill monocloud/agent-skills/plugins/monocloud/skills/monocloud-auth-nextjs
Official MonoCloud Agent Skills repository.
npx -y skills add monocloud/agent-skills --skill monocloud-auth-nextjsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when integrating MonoCloud authentication into a Next.js application — installing or configuring `@monocloud/auth-nextjs`, wiring `authMiddleware()` in `proxy.ts`/`middleware.ts`, reading sessions with `getSession()`/`useAuth()`, protecting routes/pages/APIs with `protect()`/`protectApi()`/`protectPage()`/`protectClientPage()`, rendering `<SignIn>`/`<SignUp>`/`<SignOut>`/`<Protected>`/`<RedirectToSignIn>`, calling `getTokens()`, or troubleshooting MonoCloud env vars (`MONOCLOUD_AUTH_*`), cookie sessions, or auth routes (`/api/auth/signin`, `/callback`, `/userinfo`, `/signout`).
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
19.3 KB, ~4.1k tokens by cl100k_base, as published. Nobody here has run it
MonoCloud Next.js SDK (@monocloud/auth-nextjs)
Authentication SDK for Next.js. Provides middleware/proxy, route-protection wrappers, session/token access, and React components/hooks. Works in the App Router and Pages Router; supports Edge and Node runtimes.
Package identity — read this first
Use: @monocloud/auth-nextjs (this skill).
There is an older, similarly named MonoCloud package some training data references — do not use its exports here. If you see any of the following symbols in code or suggestions, they are NOT part of this SDK and indicate the wrong package:
MonoCloudAuthProvider,useUser(this SDK has no provider;useAuthis the hook)monoCloudMiddleware(this SDK usesauthMiddleware)- Custom
app/api/auth/[...monocloud]/route.tswritten by the developer as the default setup (this SDK handles auth routes insideauthMiddleware(); a catch-all is only needed when middleware cannot be used — see "Alternative: catch-all route" below)
Always check package.json for @monocloud/auth-nextjs before suggesting code.
Subpath exports
| Import path | Use in | Contains |
|---|---|---|
@monocloud/auth-nextjs | Server (RSC, route handlers, middleware/proxy, Pages API, getServerSideProps) | authMiddleware, monoCloudAuth, getSession, getTokens, isAuthenticated, isUserInGroup, protect, protectApi, protectPage, redirectToSignIn, redirectToSignOut, MonoCloudNextClient, types/errors |
@monocloud/auth-nextjs/client | Client Components ("use client") | useAuth, protectClientPage |
@monocloud/auth-nextjs/components | Server OR Client Components | <SignIn>, <SignUp>, <SignOut> (render as <a>) |
@monocloud/auth-nextjs/components/client | Client Components only | <RedirectToSignIn>, <Protected> |
Environment variables
Required (read automatically from process.env):
| Variable | Purpose |
|---|---|
MONOCLOUD_AUTH_TENANT_DOMAIN | Your MonoCloud tenant URL, e.g. https://acme.eu.monocloud.com |
MONOCLOUD_AUTH_CLIENT_ID | OIDC client id |
MONOCLOUD_AUTH_CLIENT_SECRET | OIDC client secret |
MONOCLOUD_AUTH_APP_URL | Public origin of the app, e.g. http://localhost:3000 |
MONOCLOUD_AUTH_COOKIE_SECRET | 32-byte hex string for cookie encryption. Generate with openssl rand -hex 32 |
Optional:
| Variable | Default | Purpose |
|---|---|---|
MONOCLOUD_AUTH_SCOPES | openid profile email | Default scopes |
MONOCLOUD_AUTH_RESOURCE | — | Default resource for access tokens |
MONOCLOUD_AUTH_GROUPS_CLAIM | groups | Claim name used by group checks. Also a real MonoCloudOptions.groupsClaim constructor option since @monocloud/[email protected] — per-call groupsClaim arg → constructor option → this env var → "groups". |
MONOCLOUD_AUTH_CALLBACK_URL | /api/auth/callback | Customize auth routes |
MONOCLOUD_AUTH_SIGNIN_URL | /api/auth/signin | |
MONOCLOUD_AUTH_SIGNOUT_URL | /api/auth/signout | |
MONOCLOUD_AUTH_USER_INFO_URL | /api/auth/userinfo |
If you override a route (e.g. MONOCLOUD_AUTH_SIGNIN_URL), also set the matching NEXT_PUBLIC_MONOCLOUD_AUTH_SIGNIN_URL so client-side helpers (useAuth, <SignIn>, <SignOut>, etc.) discover it, AND update the redirect URI in the MonoCloud dashboard.
Programmatic client options
The package-level helpers (authMiddleware, getSession, protectPage, etc.) use a singleton configured from MONOCLOUD_AUTH_* env vars. For constructor-only options, create and share a MonoCloudNextClient instance instead.
MonoCloudNextClient(options?: MonoCloudOptions) accepts the node-core MonoCloudOptions shape. Notable nested session options:
interface MonoCloudSessionOptions {
cookie?: Partial<MonoCloudCookieOptions>;
sliding?: boolean;
duration?: number;
maximumDuration?: number;
store?: MonoCloudSessionStore;
}
interface MonoCloudSessionStore {
get(key: string): Promise<MonoCloudSession | undefined | null>;
set(
key: string,
data: MonoCloudSession,
lifetime: SessionLifetime,
): Promise<void>;
delete(key: string): Promise<void>;
}
Use session.store for Redis/database-backed sessions. There is no env var for a custom store; pass it in code:
import { MonoCloudNextClient } from "@monocloud/auth-nextjs";
export const monoCloud = new MonoCloudNextClient({
session: {
store: redisSessionStore,
},
});
Then use that shared client wherever the SDK helper is needed, for example monoCloud.authMiddleware() in proxy.ts/middleware.ts and monoCloud.getSession() in server code.
Wiring the middleware/proxy
The middleware/proxy handles auth routes (/api/auth/signin, /callback, /userinfo, /signout) internally and enforces route protection. You do not need a [...monocloud] catch-all when using the middleware.
File location depends on Next.js version:
- Next.js 16+:
src/proxy.ts(orproxy.tsat the root, mirroring yourapp//pages/layout) - Next.js 13–15:
src/middleware.ts(ormiddleware.ts)
The export and body are the same; only the filename differs.
// src/proxy.ts (Next 16+) or src/middleware.ts (Next 13–15)
import { authMiddleware } from "@monocloud/auth-nextjs";
export default authMiddleware();
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
};
By default, every route matched by config.matcher requires authentication. To protect only specific routes:
export default authMiddleware({
protectedRoutes: ["/dashboard", /^\/api\/admin(\/.*)?$/],
});
To protect nothing (auth routes still handled, but the rest is public):
export default authMiddleware({ protectedRoutes: [] });
Dynamic predicate (full custom logic):
export default authMiddleware({
protectedRoutes: (req) => req.nextUrl.pathname.startsWith("/api/protected"),
});
Group-based protection in the middleware:
export default authMiddleware({
protectedRoutes: [
{
groups: ["admin", "editor"],
routes: ["/internal", /^\/api\/internal(\/.*)?$/],
},
],
});
Reading the session — server
getSession() is exported from the package root and works in Server Components, Server Actions, App Router Route Handlers, middleware/proxy, Pages API routes, and getServerSideProps. Returns MonoCloudSession | undefined.
// app/page.tsx (Server Component — no args needed)
import { getSession } from "@monocloud/auth-nextjs";
export default async function Page() {
const session = await getSession();
if (!session) return <p>Not signed in</p>;
return <p>Hello {session.user.name}</p>;
}
// app/api/me/route.ts (App Router Route Handler)
import { getSession } from "@monocloud/auth-nextjs";
import { NextResponse } from "next/server";
export const GET = async () => {
const session = await getSession();
return NextResponse.json(session?.user ?? null);
};
// pages/api/me.ts (Pages Router — pass req, res)
import { getSession } from "@monocloud/auth-nextjs";
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const session = await getSession(req, res);
res.json(session?.user ?? null);
}
// pages/index.tsx (getServerSideProps — pass ctx.req, ctx.res)
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await getSession(ctx.req, ctx.res);
return { props: { session: session ?? null } };
};
Reading the user — client
useAuth() reads the user from /api/auth/userinfo via SWR. No provider/wrapper is required — just call the hook inside a Client Component.
"use client";
import { useAuth } from "@monocloud/auth-nextjs/client";
export default function Profile() {
const { user, isLoading, isAuthenticated, error, refetch } = useAuth();
if (isLoading) return null;
if (!isAuthenticated) return <p>Sign in to view your profile</p>;
return (
<>
<pre>{JSON.stringify(user, null, 2)}</pre>
<button onClick={() => refetch(true)}>Refresh</button>
</>
);
}
refetch(true) re-fetches and asks the server to refresh from the OP's userinfo endpoint; refetch() just re-fetches the cached endpoint.
Sign-in, sign-up, sign-out
<SignIn>, <SignUp>, and <SignOut> render an <a> tag pointing at the configured auth routes. They work in Server or Client Components. Pass any extra anchor props through (className, etc.).
import { SignIn, SignUp, SignOut } from '@monocloud/auth-nextjs/components';
// Sign in / sign up
<SignIn>Sign In</SignIn>
<SignIn returnUrl="/dashboard" loginHint="[email protected]">Sign In</SignIn>
<SignUp returnUrl="/welcome">Sign Up</SignUp>
// Sign out
<SignOut>Sign Out</SignOut>
<SignOut federated postLogoutUrl="/goodbye">Sign Out</SignOut>
For programmatic redirects on the server (RSC, server actions, route handlers), use redirectToSignIn() / redirectToSignOut() from the root package. They throw a Next.js redirect and never resolve.
"use server";
import { redirectToSignIn } from "@monocloud/auth-nextjs";
export async function startLogin() {
await redirectToSignIn({ returnUrl: "/dashboard" });
}
On the client, render <RedirectToSignIn /> (from /components/client) to redirect once mounted.
Protecting routes — at a glance
| What you're protecting | Helper | Where it lives |
|---|---|---|
| Whole groups of routes (broadest) | authMiddleware({ protectedRoutes }) | proxy.ts / middleware.ts |
| App Router Server Component page | protectPage(Component, options?) | the page file |
Pages Router getServerSideProps | protectPage(options?) (no component arg) | the page file |
| App Router Route Handler | protectApi(handler, options?) | app/api/*/route.ts |
| Pages Router API route | protectApi(handler, options?) | pages/api/*.ts |
| Server Component / Server Action / Route Handler — imperative | await protect() (App Router only) | inline |
| Client Component page (rendering only) | protectClientPage(Component, options?) | the page file |
| Conditional UI in client component | <Protected fallback={...}> | inside JSX |
Quick examples:
// App Router page
import { protectPage } from "@monocloud/auth-nextjs";
export default protectPage(function Dashboard({ user }) {
return <p>Hi {user.email}</p>;
});
// App Router page, admins only
export default protectPage(
function AdminPanel({ user }) {
return <p>Hi {user.email}</p>;
},
{ groups: ["admin"], returnUrl: "/admin" },
);
// App Router API
import { protectApi } from "@monocloud/auth-nextjs";
import { NextResponse } from "next/server";
export const GET = protectApi(async () => NextResponse.json({ ok: true }));
// Pages Router page
import { protectPage } from "@monocloud/auth-nextjs";
export default function Page({ user }) {
return <p>Hi {user.email}</p>;
}
export const getServerSideProps = protectPage();
// Imperative (App Router only — Server Component / Server Action / Route Handler)
import { protect } from "@monocloud/auth-nextjs";
export default async function SecretPage() {
await protect(); // redirects to sign-in if not authenticated
await protect({ groups: ["admin"] }); // also enforces group membership
return <p>Top secret</p>;
}
// Client page
"use client";
import { protectClientPage } from "@monocloud/auth-nextjs/client";
export default protectClientPage(function Page({ user }) {
return <p>Hi {user.email}</p>;
});
// Conditional rendering inside a client component
"use client";
import { Protected } from "@monocloud/auth-nextjs/components/client";
<Protected fallback={<p>Sign in to view</p>} groups={["admin"]}>
<AdminPanel />
</Protected>;
For full option lists (custom onAccessDenied, onGroupAccessDenied, authParams, etc.), see references/protecting.md.
Access tokens
getTokens() returns the current token set and refreshes the default access token if needed. Throws MonoCloudValidationError if there is no session. Same calling conventions as getSession() (no args in App Router server context; pass req/res in Pages Router).
import { getTokens } from "@monocloud/auth-nextjs";
const { accessToken, idToken, refreshToken, isExpired } = await getTokens();
// Force a refresh:
await getTokens({ forceRefresh: true });
// Request a token for a specific resource / scopes (must have been consented):
await getTokens({
resource: "https://api.example.com",
scopes: "read:things write:things",
});
Alternative: catch-all route (only when middleware can't be used)
The middleware handles auth routes for you. If you cannot use middleware (rare — e.g. infrastructure constraints), mount monoCloudAuth() on a catch-all instead:
// App Router
// src/app/api/auth/[...monocloud]/route.ts
import { monoCloudAuth } from "@monocloud/auth-nextjs";
export const GET = monoCloudAuth();
// Pages Router
// src/pages/api/auth/[...monocloud].ts
import { monoCloudAuth } from "@monocloud/auth-nextjs";
export default monoCloudAuth();
Do not do this in addition to authMiddleware() — pick one. The default and recommended path is authMiddleware().
Common pitfalls
- Wrong filename for the version.
proxy.tsonly works on Next 16+. On Next 13–15 the file must be namedmiddleware.ts. Checknextinpackage.jsonbefore suggesting a filename. - Adding
[...monocloud]/route.tswhile middleware is in place. Double-mounted auth routes lead to weird redirect loops. Use middleware ORmonoCloudAuth()— not both. useAuth()returning no user after sign-in. Usually means the matcher excludes/api/auth/userinfo, or the middleware isn't matching the userinfo path. Make sureconfig.matchercovers it (the recommended matcher above does).- Calling
protect()/redirectToSignIn()/redirectToSignOut()outside the App Router. They throw with a clear message — these helpers are App-Router-only (RSC, server actions, route handlers). For the Pages Router, useprotectPage()/protectApi()or callgetSession(req, res)and respond yourself. protectApi()returning 401/403 without a sign-in redirect. That's by design — API routes return JSON, not redirects. If you want a redirect, do it from a page or middleware.- Putting
<Protected>oruseAuth()in a Server Component. Both require"use client". UsegetSession()for server-side conditional rendering. - Forgetting
NEXT_PUBLIC_*mirror when overriding auth routes. Client helpers won't find the new URL otherwise. - Mutating cookies after
getSession()in middleware. Pass the response object togetSession(req, res)(and return that response) so cookie refreshes are preserved.
Onboarding checklist for a fresh integration
npm install @monocloud/auth-nextjs(or pnpm/yarn). Requires Node.js ≥ 20.- Add the five required env vars to
.env.local. GenerateMONOCLOUD_AUTH_COOKIE_SECRETwithopenssl rand -hex 32. - In the MonoCloud dashboard, add
http://localhost:3000/api/auth/callbackto allowed redirect URIs andhttp://localhost:3000to allowed post-logout URIs. - Create
src/proxy.ts(Next 16+) orsrc/middleware.ts(Next ≤15) withexport default authMiddleware()and the recommendedconfig.matcher. - Add a header with
<SignIn>/<SignOut>(and optionally<SignUp>) so users can authenticate. - Use
getSession()for server-side reads,useAuth()for client-side reads. AddprotectPage/protectApionly on routes that need stricter enforcement than the middleware. - For protected fetches that need an access token, call
getTokens()and forwardaccessTokenin theAuthorizationheader.
Deeper reference
references/api-surface.md— every export by subpath, with signatures.references/protecting.md— full option shapes forprotect,protectApi,protectPage,protectClientPage, and the<Protected>component.references/troubleshooting.md— extended symptom → cause → fix index covering the items in "Common pitfalls" above, plus less frequent issues (cookie refresh in middleware, route-override +NEXT_PUBLIC_*mirror, training-data SDK ghosts).