nextauthjs / next-auth

Authentication for the Web.

Home Page:https://authjs.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support multiple SAML 2 Identity Providers (IDP)

nick-myers-dt opened this issue Β· comments

Summary of proposed feature
Allow users of a SAML 2.0 Identity Provider (IDP) to sign in using next-auth

Purpose of proposed feature
In the education sector, many organisations use a SAML 2 IDP to authenticate their users (e.g. students) and seek to use third party services which allow their users to sign in to the third party service using their own IDP. This means that businesses that sell into the education sector must provide sign in capabilities using SAML.

Detail about proposed feature
next-auth would allow configuration of email domains which would redirect users who enter an email address in that domain to the relevant IDP. This is referred to as Identity Provider Discovery.

next-auth would allow configuration of metadata to be exchanged during authentication process.

Essentially, next-auth would allow itself to be set-up as a SAML 2 Service Provider (SP)

Potential problems
SAML 2 is pretty well established as a standard, I don't perceive any possible problems.

Describe any alternatives you've considered
A clear and concise description of any alternative options you've considered.

Additional context
Understanding SAML on Okta.com
Identity Provider Discovery on Shibboleth.net
SAML Service Provider on Auth0.com

Please indicate if you are willing and able to help implement the proposed feature.
I don't think I have the technical expertise to do so!

Thanks for the feature request and for the relevant links.

Oh SAML gives me horrible flashbacks to supporting SSO with it years ago. πŸ™€

Given my experience with it and I as have no need to work on this, it's not something I'd work on for free, but it's a reasonable feature request and I'd happy accept adding this as a pull request.

Maybe someone else who wants it will see this and pick it up.

If anyone would like integrate with SAML service in the meantime, you should be able to do it using a combination of a custom sign in page / Credentials Provider / signin() callback, without having to actually modify next-auth to add native support for SAML.

You could possibly even create a Provider based on the Credentials Provider that was specific to supporting sign in with SAML.

You could also use integration with Okta and/or Auth0 to handle this - while they are also in many respects alternatives to NextAuth.js, but NextAuth.js also works great with both of them!

Those horrible flashbacks are exactly the scenarios I'm thinking of! Totally understand it not being something 'core' and so shouldn't fall to you to implement. The existing supported standards provide a wealth of sign on providers, and as you point out there are other ways to achieve it.

Thanks for keeping the request open, be interesting to see if any others have this need.

While I'm here - awesome work on next-auth!

Hey, for reference -- I got this working! I'm still figuring out the custom sign-in page for SP-initiated flow but using samlify I ended up able to make a custom acs endpoint like so:

import axios from 'axios'
import { NextApiRequest, NextApiResponse } from 'next'
import publicConfig from '../../../config/public'

export default async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {
  if (req.method !== 'POST') {
    res.status(405).end()
    return
  }
  try {
    // First, grab a CSRF token.
    const result = await axios('/api/auth/csrf', { baseURL: publicConfig.urlBase })
    const { csrfToken } = result.data

    // Then, encode the SAML body to be sent as a "credential" and parsed.
    const encodedSAMLBody = encodeURIComponent(JSON.stringify(req.body))

    // Some good old-fashioned regular HTML to autosubmit on the client side
    res.setHeader('set-cookie', result.headers.get('set-cookie') ?? '')
    res.send(
      `<html>
        <body>
          <form action="/api/auth/callback/saml" method="POST">
            <input type="hidden" name="csrfToken" value="${csrfToken}"/>
            <input type="hidden" name="samlBody" value="${encodedSAMLBody}"/>
          </form>
          <script>
            document.forms[0].submit();
          </script>
        </body>
      </html>`
    )
  } catch (e) {
    console.log({ error: e, message: 'Error while processing SAML response' })
    res.status(403).end()
  }
}

With a provider like so (where $SamlService is just an object wrapping the initializer for Samlify):

        Providers.Credentials({
          id: 'saml',
          name: 'Okta SAML',
          credentials: {},
          authorize: async (body: { samlBody: string }) => {
            const samlBody = JSON.parse(decodeURIComponent(body.samlBody))
            const idp = await $SamlService.getIDP()
            const sp = await $SamlService.getSP()
            const { extract } = await sp.parseLoginResponse(idp, 'post', { body: samlBody })
            if (!extract.attributes.role) {
              throw new Error('SAML middleware does not provide any Agent response')
            }
            const { role, userID } = extract.attributes
            return {
              sub: userID,
              role,
            }
          },
        }),

Does this sound about right? And is there any interest in sort of massaging this flow into next-auth proper as a PR with a "saml" provider where perhaps the callback can be directly hit as the /acs endpoint (so I can get around the /acs endpoint dance where I have to provide a CSRF token)?

I can help with this, if folks wanting to integrate saml are willing to add another service to their stack

I maintain Osso, a SAML to OAuth bridge - https://github.com/enterprise-oss/osso

We'd be happy to create a PR here to add Osso as a service that consumes an Osso instance. Osso handles the saml config and authentication, and your nextjs site would consume Osso as an OAuth 2.0 service in a auth code grant flow

πŸŽ‰ This issue has been resolved in version 3.10.0 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

πŸŽ‰ This issue has been resolved in version 4.0.0-next.5 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€