Example SAML authentication app using Next.js App Router (RSC) and OneLogin SSO. Uses:
- Next.js Middleware for checking if a user is logged in (see
middleware.ts
) - Next.js Route Handlers for:
- generating and redirecting to the OneLogin SAML login URL (see
app/login/sso/route.ts
) - handling the OneLogin SAML callback POST request and storing the user in a session cookie (see
app/login/sso/callback/route.ts
)
- generating and redirecting to the OneLogin SAML login URL (see
- the
node-saml
library (see configuration inauth.ts
) - a cookie-based session based on this example and the Next.js docs (see
auth.ts
) - TypeScript
See the passport-saml
source code for more robust auth handling.
- create OneLogin developer account here: https://developers.onelogin.com/
- for example, use the domain
your-domain
- at https://your-domain-dev.onelogin.com/admin2/apps select "Add App" > "SAML Custom Connector (Advanced)"
- on "Configuration" tab, set the following 5 fields:
- "Audience (EntityID)" [1]:
your-example-app
- "Recipient":
your-example-app
- "ACS (Consumer) URL Validator*":
http://localhost:3000/login/sso/callback
- "ACS (Consumer) URL*":
http://localhost:3000/login/sso/callback
- "SAML signature event" [1]: "Both"
- "Audience (EntityID)" [1]:
[1] required as of node-saml
v4.0.0
- copy
.env.example
to.env
and change the following:SSO_ENTRYPOINT
: "SSO" tab > "SAML 2.0 Endpoint (HTTP)"SSO_CERT
: "SSO" tab > "X.509 Certificate" > "View Details" > "X.509 Certificate" with "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" and newlines removedSSO_COOKIE_SESSION_SECRET
: generate or make up a secret string
Note: SSO_ISSUER
should be "Recipient" on the "Configuration" tab and SSO_CALLBACK_URL
should be "ACS (Consumer) URL*" on the "Configuration" tab.
Example .env
SSO_ENTRYPOINT='https://your-domain-dev.onelogin.com/trust/saml2/http-post/sso/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
SSO_ISSUER='your-example-app'
SSO_CALLBACK_URL='http://localhost:3000/login/sso/callback'
SSO_CERT='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX='
SSO_COOKIE_SESSION_SECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$ npm install
$ npm run dev
Go to http://localhost:3000 in the browser
- GET http://localhost:3000 (redirect to #2 if not logged in)
- GET http://localhost:3000/login/sso
- GET https://your-domain-dev.onelogin.com/trust/saml2/http-post/sso/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- POST http://localhost:3000/login/sso/callback
- GET http://localhost:3000 (with user session cookie)
- https://github.com/saltycrane/express-node-saml-example
- https://nextjs.org/docs/app/building-your-application/authentication
- https://www.youtube.com/watch?v=DJvM2lSPn6w
- https://github.com/balazsorban44/auth-poc-next
- https://github.com/node-saml/passport-saml/blob/master/src/strategy.ts
- ensure your user is added to the default role for the app in the OneLogin admin UI.
- go to https://your-domain.onelogin.com/roles
- select the "Default" role
- select the "Users" tab
- ensure your user is added to that role or add it
- in the OneLogin admin UI, in the "Configuration" tab, ensure that "SAML signature element" is set to "Both"
- alternatively, as a less secure option, add the following configuration to the
passport-saml
Strategy
:wantAssertionsSigned: false
. node-saml
changed in v4.0.0 to require all assertions be signed. See node-saml/node-saml#177
- in
node-saml
,audience
defaults to the value ofissuer
- in the OneLogin admin UI, in the "Configuration" tab, ensure that "Audience (EntityID)" is the same as
issuer
. (In this example it is the value of "Recipient",your-example-app
)