DEV Community

Abhishek Dave for SSOJet

Posted on • Originally published at ssojet.com on

Integrating Okta SAML SSO with Your Next.js Application

Single Sign-On (SSO) streamlines user access and enhances security by allowing users to log in once and access multiple applications. Okta is a leading Identity Management provider, and SAML (Security Assertion Markup Language) is a robust standard for exchanging authentication and authorization data.

Combining Okta’s identity platform with SAML in your Next.js application offers a secure and user-friendly authentication experience. This guide will walk you through the essential steps to implement Okta SAML SSO in your Next.js project.

Why Okta + SAML + Next.js?

  • Centralized Authentication: Manage users and access policies in one place (Okta).
  • Improved User Experience: Users log in once via Okta to access your Next.js app and potentially others.
  • Enhanced Security: Leverage Okta’s security features (MFA, adaptive policies) and the secure nature of SAML assertions.
  • Scalability: Suitable for enterprise environments with many users and applications.

Prerequisites:

  1. Okta Developer Account: You’ll need an Okta account (a free developer account works perfectly for testing).
  2. Node.js & npm/yarn: Ensure Node.js (which includes npm) or yarn is installed on your system.
  3. Next.js Project: A basic understanding of Next.js and an existing or new project (npx create-next-app@latest my-okta-saml-app).
  4. Domain/URL: You need a publicly accessible URL for Okta to redirect back to during the authentication flow. For local development, tools like ngrok are invaluable.

Step 1: Configure the SAML Application in Okta

  1. Log in to your Okta Admin Dashboard.
  2. Navigate to Applications > Applications.
  3. Click Create App Integration.
  4. Select SAML 2.0 and click Next.
  5. App Name: Give your application a descriptive name (e.g., “Next.js SAML App”). Add a logo if desired. Click Next.
  6. Configure SAML: This is the crucial part.
    • Single sign on URL (ACS URL): This is the URL in your Next.js application where Okta will send the SAML assertion after successful authentication. It will typically be an API route like https://<your-domain>/api/auth/saml/callback. Remember to replace <your-domain> with your actual domain or ngrok URL.
    • Audience URI (SP Entity ID): A unique identifier for your application. It’s common practice to use the same URL as the ACS URL, or a unique URN like urn:example:nextjs-saml. This value must match what you configure in your Next.js app.
    • Default RelayState: Leave blank unless you have specific needs.
    • Name ID format: Usually EmailAddress.
    • Application username: Select the Okta attribute that maps to the user’s identifier in your app (e.g., Email or Okta username).
    • Attribute Statements (Optional but Recommended): Add attributes you want Okta to send in the SAML assertion (e.g., firstName, lastName, email). Define the Name (e.g., email) and select the corresponding Okta User Profile value (e.g., user.email). Your Next.js app will parse these.
  7. Single sign on URL (ACS URL): This is the URL in your Next.js application where Okta will send the SAML assertion after successful authentication. It will typically be an API route like https://<your-domain>/api/auth/saml/callback. Remember to replace <your-domain> with your actual domain or ngrok URL.
  8. Audience URI (SP Entity ID): A unique identifier for your application. It’s common practice to use the same URL as the ACS URL, or a unique URN like urn:example:nextjs-saml. This value must match what you configure in your Next.js app.
  9. Default RelayState: Leave blank unless you have specific needs.
  10. Name ID format: Usually EmailAddress.
  11. Application username: Select the Okta attribute that maps to the user’s identifier in your app (e.g., Email or Okta username).
  12. Attribute Statements (Optional but Recommended): Add attributes you want Okta to send in the SAML assertion (e.g., firstName, lastName, email). Define the Name (e.g., email) and select the corresponding Okta User Profile value (e.g., user.email). Your Next.js app will parse these.
  13. Click Next.
  14. Feedback: Select “I’m an Okta customer adding an internal app” or the appropriate option and click Finish.
  15. Get Okta IdP Metadata: Once the app is created, go to the Sign On tab. Find the Metadata URL under “SAML Signing Certificates”. You’ll need this URL or the contents of the XML file it points to (specifically the IdP’s entry point URL and the signing certificate). Keep this tab open or copy the Metadata URL.

Step 2: Set Up Your Next.js Project for SAML

While next-auth (now Auth.js) is popular for Next.js authentication, direct SAML support often requires custom providers or can be complex. A common approach for Node.js (and thus Next.js API routes) is using passport with the passport-saml strategy.

  1. Install Dependencies:

  2. passport: Authentication middleware framework.

  3. passport-saml: Passport strategy for SAML 2.0.

  4. express-session / iron-session: For managing user sessions server-side. iron-session is often preferred for Next.js as it’s designed for serverless environments.

  5. Environment Variables: Store your Okta configuration securely. Create a .env.local file in your project root:

  6. Important: Ensure OKTA_CERT contains the full certificate text, including the BEGIN/END lines, with newline characters (\n) preserved if pasting directly into the .env file.

Step 3: Implement Authentication Logic in API Routes

We’ll use Next.js API routes (pages/api/) to handle the SAML flow.

  1. Configure Passport & Session: Create a utility file (e.g., lib/auth.js) to configure Passport and session handling.

  2. Login Route: Create pages/api/auth/saml/login.js. This route initiates the SAML flow by redirecting the user to Okta.

  3. Callback Route: Create pages/api/auth/saml/callback.js. This is the ACS URL where Okta redirects back. Passport processes the SAML assertion here.

  4. Logout Route: Create pages/api/auth/logout.js.

  5. User Info Route (Optional): Create an endpoint to fetch the current user’s session data for the client-side.

Step 4: Protect Pages and Manage Client-Side State

  1. Protecting Server-Rendered Pages: Use withSessionSsr in getServerSideProps for pages that require authentication.

  2. Client-Side Authentication Check: Use a library like SWR or React Query to fetch user status from the /api/user endpoint.

Step 5: Testing

  1. Start your Next.js development server (npm run dev).
  2. If developing locally, start ngrok (ngrok http 3000) and update your Okta application’s ACS URL and Audience URI, as well as your .env.local file (APP_CALLBACK_URL, APP_AUDIENCE, NEXT_PUBLIC_APP_URL) with the https ngrok URL.
  3. Ensure your user is assigned to the SAML application in Okta.
  4. Navigate to your application’s login initiation point (e.g., click the “Login with Okta” link which points to /api/auth/saml/login).
  5. You should be redirected to Okta for authentication.
  6. After successful login, Okta should redirect you back to your /api/auth/saml/callback URL.
  7. The callback handler should process the assertion, create a session, and redirect you to your dashboard or home page, now showing you as logged in.
  8. Test the logout functionality.

Important Considerations & Next Steps:

  • Security:
    • HTTPS: Always use HTTPS in production for both your app and the Okta communication.
    • Environment Variables: Never commit secrets (.env.local, certificates) to version control. Use environment variables in your deployment environment.
    • Session Secret: Use a strong, unique SESSION_SECRET.
    • Certificate Management: Keep the Okta IdP certificate updated. Okta provides mechanisms for certificate rotation.
    • Assertion Validation: passport-saml handles much of the validation, but ensure your configuration is strict (e.g., checking audience, timestamps).
  • HTTPS: Always use HTTPS in production for both your app and the Okta communication.
  • Environment Variables: Never commit secrets (.env.local, certificates) to version control. Use environment variables in your deployment environment.
  • Session Secret: Use a strong, unique SESSION_SECRET.
  • Certificate Management: Keep the Okta IdP certificate updated. Okta provides mechanisms for certificate rotation.
  • Assertion Validation: passport-saml handles much of the validation, but ensure your configuration is strict (e.g., checking audience, timestamps).
  • Error Handling: Implement more robust error handling and user feedback on login/callback failures.
  • User Provisioning: Decide how users are created/managed in your application’s database upon first SAML login.
  • Single Logout (SLO): For a more complete SSO experience, implement SAML SLO where logging out of Okta or another SAML app can log the user out of your Next.js app, and vice-versa. This requires additional configuration in Okta and your passport-saml setup.
  • Alternative: OIDC with Auth.js: While this guide focuses on SAML, Okta also strongly supports OpenID Connect (OIDC). OIDC is often considered simpler to integrate with modern web frameworks using libraries like Auth.js (next-auth), which has built-in support for OIDC providers like Okta. Consider OIDC if you don’t have a strict requirement for SAML.

Integrating Okta SAML into Next.js involves careful configuration on both the Okta and application sides. By using libraries like passport-saml and managing sessions correctly within Next.js API routes, you can build a secure and seamless SSO experience for your users. Remember to prioritize security and thoroughly test your implementation.

Top comments (0)