Implement 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).
- 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: openid-client (standard for Node.js OIDC integration).
- 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.
- 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; }
- 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 /api/auth/callback and then to /dashboard .
- 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 CLIENT_SECRET and ISSUER_URL in .env.local and access them via process.env .
- 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.