Skills oidc-hosted-page-nextjs
Implement "Sign in with SSO" in Next.js applications using SSOJet OIDC Authorization Code flow with the App Router.
git clone https://github.com/ssojet/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/ssojet/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/authentication/oidc-hosted-page-nextjs" ~/.claude/skills/ssojet-skills-oidc-hosted-page-nextjs && rm -rf "$T"
skills/authentication/oidc-hosted-page-nextjs/SKILL.mdImplement SSOJet OIDC (Next.js)
This expert AI assistant guide walks you through integrating "Sign in with SSO" functionality into an existing login page in a Next.js application using SSOJet as an OIDC identity provider. The goal is to modify the existing login flow to add SSO support without disrupting the current traditional login functionality (e.g., email/password).
1. Prerequisites
- An existing Next.js application with a login page.
- Basic knowledge of Next.js and its common tools (e.g., App Router).
- An active SSOJet account.
- SSO Connection Setup Guide
- Required libraries:
(standard for Node.js OIDC integration).openid-client
2. Implementation Steps
Step 1: Create Application in SSOJet
- Log in to the SSOJet Dashboard.
- Navigate to Applications.
- Create a new application (e.g., "MyNextjsApp", type Regular Web App).
- Configure the callback URI (e.g.,
).http://localhost:3000/api/auth/callback - Retrieve Client ID and Client Secret.
- Copy the Issuer URL from the Advanced > Endpoints section.

Step 2: Modify the Existing Next.js Project
Substep 2.1: Install Dependencies
Run the following command to install the required OIDC library:
npm install openid-client
Substep 2.2: Configure OIDC
Configure the OIDC provider with your SSOJet credentials. It is recommended to create a dedicated utility file for this configuration (e.g.,
lib/oidc.ts).
// lib/oidc.ts import { Issuer } from 'openid-client'; export async function getClient() { const ssojetIssuer = await Issuer.discover('${ISSUER_URL}'); // e.g. https://auth.ssojet.com return new ssojetIssuer.Client({ client_id: '${cli_curf51oulvtc716e50eg.ad4a67ec19ac4507b744a1686ec9bff8.MGMpt3uV99Lftv5KkHF7pk}', client_secret: '${CLIENT_SECRET}', redirect_uris: ['http://localhost:3000/api/auth/callback'], response_types: ['code'], }); }
Substep 2.3: Update Login Page/UI
Modify your existing login component (e.g.,
app/login/page.tsx) to include the "Sign in with SSO" toggle.
'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; export default function LoginPage() { const [isSSO, setIsSSO] = useState(false); const [email, setEmail] = useState(''); const router = useRouter(); const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); if (isSSO) { // Trigger SSO login by redirecting to our API route window.location.href = `/api/auth/login?login_hint=${encodeURIComponent(email)}`; } else { // Existing password login logic here console.log('Processing traditional login...'); } }; return ( <div className="login-container"> <h1>Sign In</h1> <form onSubmit={handleLogin} className="flex flex-col gap-4"> <div> <label>Email</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required className="border p-2 rounded" /> </div> {!isSSO && ( <div> <label>Password</label> <input type="password" required className="border p-2 rounded" /> </div> )} <button type="submit" className="bg-blue-600 text-white p-2 rounded"> {isSSO ? 'Continue with SSO' : 'Sign In'} </button> <button type="button" onClick={() => setIsSSO(!isSSO)} className="text-sm text-blue-500 underline" > {isSSO ? 'Back to Password Login' : 'Sign in with SSO'} </button> </form> </div> ); }
Substep 2.4: Update Backend Logic
Create the necessary API routes to handle the OIDC flow.
1. Login Initiation Route (
app/api/auth/login/route.ts):
import { NextResponse } from 'next/server'; import { getClient } from '@/lib/oidc'; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const login_hint = searchParams.get('login_hint'); const client = await getClient(); // Generate a random state for CSRF protection const state = Math.random().toString(36).substring(2, 15); const authorizationUrl = client.authorizationUrl({ scope: 'openid profile email', login_hint: login_hint || undefined, state, }); const response = NextResponse.redirect(authorizationUrl); // Store state in a cookie to verify in the callback response.cookies.set('oidc_state', state, { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 3600 }); return response; }
2. Callback Handler Route (
app/api/auth/callback/route.ts):
import { NextRequest, NextResponse } from 'next/server'; import { getClient } from '@/lib/oidc'; export async function GET(request: NextRequest) { const client = await getClient(); const params = client.callbackParams(request.url); try { const storedState = request.cookies.get('oidc_state')?.value; const tokenSet = await client.callback('http://localhost:3000/api/auth/callback', params, { state: storedState }); const userinfo = await client.userinfo(tokenSet.access_token!); // TODO: Create a session for the user based on `userinfo` console.log('Authenticated User:', userinfo); // Redirect to the dashboard or intended page return NextResponse.redirect(new URL('/dashboard', request.url)); } catch (error) { console.error('OIDC Callback Error:', error); return NextResponse.redirect(new URL('/login?error=oidc_failed', request.url)); } }
Step 3: Test the Modified Connection
- Start your application:
.npm run dev - Navigate to your login page (e.g.,
)./login - Verify that the traditional login form (Email + Password) is visible by default.
- Click "Sign in with SSO" and ensure:
- The password field disappears.
- The submit button changes to "Continue with SSO".
- Enter a test email and submit.
- You should be redirected to the SSOJet login page.
- Authenticate with SSOJet.
- You should be redirected back to
and then to/api/auth/callback
./dashboard
- You should be redirected back to
3. Additional Considerations
- Error Handling: Enhance the callback route to handle specific OIDC errors gracefully.
- Styling: Adapt the example CSS classes to match your application's design system.
- Security: Integrate the user information returned in the callback with your existing session management system (e.g., setting cookies or JWTs).
- Environment Variables: Store sensitive values like
andCLIENT_SECRET
inISSUER_URL
and access them via.env.local
.process.env
4. Support
- Contact SSOJet support: Reach out if you have integration questions.
- Check application logs: Use server-side logging to debug OIDC flow issues.
- Library Documentation: Refer to the openid-client documentation for advanced configuration.