Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple SAML 2 Identity Providers (IDP) #311

Closed
nick-myers-dt opened this issue Jun 23, 2020 · 6 comments · Fixed by #1448
Closed

Support multiple SAML 2 Identity Providers (IDP) #311

nick-myers-dt opened this issue Jun 23, 2020 · 6 comments · Fixed by #1448
Labels
enhancement New feature or request

Comments

@nick-myers-dt
Copy link

nick-myers-dt commented Jun 23, 2020

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!

@nick-myers-dt nick-myers-dt added the enhancement New feature or request label Jun 23, 2020
@iaincollins
Copy link
Member

iaincollins commented Jun 23, 2020

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!

@nick-myers-dt
Copy link
Author

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!

@daviduzumeri
Copy link

daviduzumeri commented Oct 6, 2020

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)?

@stale stale bot added the wontfix This will not be worked on label Dec 5, 2020
@balazsorban44 balazsorban44 added stale Did not receive any activity for 60 days and removed wontfix This will not be worked on labels Dec 5, 2020
@sbauch
Copy link
Contributor

sbauch commented Dec 7, 2020

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

@stale stale bot removed the stale Did not receive any activity for 60 days label Dec 7, 2020
@stale stale bot added the stale Did not receive any activity for 60 days label Feb 5, 2021
@stale stale bot closed this as completed Feb 12, 2021
@balazsorban44 balazsorban44 reopened this Mar 5, 2021
@stale stale bot removed the stale Did not receive any activity for 60 days label Mar 5, 2021
@nextauthjs nextauthjs deleted a comment from stale bot Mar 5, 2021
@nextauthjs nextauthjs deleted a comment from stale bot Mar 5, 2021
@nextauthjs nextauthjs deleted a comment from stale bot Mar 5, 2021
@github-actions
Copy link

github-actions bot commented Mar 5, 2021

🎉 This issue has been resolved in version 3.10.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This issue has been resolved in version 4.0.0-next.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants