Breached password detection is a critical component of secure applications.    Read the white paper

FusionAuth logo
FusionAuth logo
  • Features
    FusionAuth Reactor

    FusionAuth Reactor is a powerful suite of features developed to extend FusionAuth's core functionality.

    • Flexible Architecture   Flexible Architecture
    • Auth the Way You Want It   Auth the Way You Want It
    • Security & Compliance   Security & Compliance
    • Ultimate Password Control   Ultimate Password Control
    • Customizable User Experience   Customizable User Experience
    • Advanced Registration Forms   Advanced Registration Forms
    • Built for Devs   Built for Devs
    • User Management & Reporting   User Management & Reporting
    • Scalability   Scalability
    • Single Sign-on   Single Sign-on
    • Breached Password Detection   Breached Password Detection
    • Connectors   Connectors
    • FusionAuth Reactor   FusionAuth Reactor
  • Pricing
    Cloud Pricing

    Let us host, monitor, manage, and maintain your deployments in your own private cloud.

    SEE PRICING cloud pricing   See FusionAuth Cloud Pricing
    Editions Pricing

    A powerful set of features with available support that extends FusionAuth's core functionality.

    SEE PRICING edition pricing   See FusionAuth Edition Pricing
    Editions + Cloud

    FusionAuth will handle everything so you can get back to building something awesome.

    GET STARTED Get started
  • Docs
  • Downloads
  • Resources
    FusionAuth Resources
    • Upgrade from SaaS
    • Upgrade from Open Source
    • Upgrade from Home Grown
    • Blog   Blog
    • Forum   Forum
    • Community & Support   Community & Support
    • Customer & Partners   Customers & Partners
    • Video & Podcasts   Videos & Podcasts
    • Getting Started   Getting Started
  • Expert Advice
    Expert Advice for Developers

    Learn everything you need to know about authentication, authorization, identity, and access management from our team of industry experts.

    • Authentication   Authentication
    • CIAM   CIAM
    • Identity Basics   Identity Basics
    • OAuth   OAuth
    • Security   Security
    • Tokens   Tokens
    • Dev Tools   Dev Tools
  • Account
Navigate to...
  • Welcome
  • Getting Started
  • 5-Minute Setup Guide
  • Reactor
  • Core Concepts
    • Overview
    • Users
    • Roles
    • Groups
    • Registrations
    • Applications
    • Tenants
    • Identity Providers
    • Authentication and Authorization
    • Integration Points
    • Roadmap
  • Installation Guide
    • Overview
    • System Requirements
    • Server Layout
    • Cluster
    • Docker
    • Fast Path
    • Kickstart™
    • Homebrew
    • Packages
    • Database
    • FusionAuth App
    • FusionAuth Search
    • Securing
    • Upgrading
  • APIs
    • Overview
    • Authentication
    • Errors
    • Actioning Users
    • Applications
    • Audit Logs
    • Connectors
      • Overview
      • Generic
      • LDAP
    • Consent
    • Emails
    • Event Logs
    • Families
    • Forms
    • Form Fields
    • Groups
    • Identity Providers
      • Overview
      • Apple
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Twitter
      • OpenID Connect
      • SAML v2
      • External JWT
    • Integrations
    • JWT
    • Keys
    • Lambdas
    • Login
    • Passwordless
    • Registrations
    • Reports
    • System
    • Tenants
    • Themes
    • Two Factor
    • Users
    • User Actions
    • User Action Reasons
    • User Comments
    • Webhooks
  • Client Libraries
    • Overview
    • Dart
    • Go
    • Java
    • JavaScript
    • .NET Core
    • Node
    • PHP
    • Python
    • Ruby
    • Typescript
  • Themes
    • Overview
    • Localization
    • Examples
  • Email & Templates
    • Overview
    • Configure Email
    • Email Templates
  • Events & Webhooks
    • Overview
    • Events
    • Writing a Webhook
    • Securing Webhooks
  • Example Apps
    • Overview
    • Go
    • Java
    • JavaScript
    • .NET Core
    • PHP
    • Python
    • Ruby
  • Lambdas
    • Overview
    • Apple Reconcile
    • External JWT Reconcile
    • Facebook Reconcile
    • Google Reconcile
    • HYPR Reconcile
    • JWT Populate
    • LDAP Connector Reconcile
    • LinkedIn Reconcile
    • OpenID Connect Reconcile
    • SAML v2 Populate
    • SAML v2 Reconcile
    • Twitter Reconcile
  • Identity Providers
    • Overview
    • Apple
    • Facebook
    • Google
    • HYPR
    • LinkedIn
    • Twitter
    • OpenID Connect
      • Overview
      • Azure AD
      • Github
      • Discord
    • SAML v2
      • Overview
      • ADFS
    • External JWT
      • Overview
      • Example
  • Connectors
    • Overview
    • Generic Connector
    • LDAP Connector
    • FusionAuth Connector
  • Integrations
    • Overview
    • CleanSpeak
    • Kafka
    • Twilio
  • OpenID Connect & OAuth 2.0
    • Overview
    • Endpoints
    • Tokens
  • SAML v2 IdP
    • Overview
    • Google
    • Zendesk
  • Plugins
    • Writing a Plugin
    • Password Encryptors
  • Guides
    • Overview
    • Advanced Registration Forms
    • Breached Password Detection
    • Migration
    • Passwordless
    • Securing Your APIs
    • Silent Mode
    • Single Sign-on
  • Tutorials
    • Overview
    • Setup Wizard & First Login
    • Register/Login a User
    • Migrate Users
    • JSON Web Tokens
    • Authentication Tokens
    • Start and Stop FusionAuth
    • Switch Search Engines
    • User Account Lockout
    • Two Factor
  • Reference
    • CORS
    • Configuration
    • Data Types
    • Known Limitations
    • Password Encryptors
  • Release Notes
  • Troubleshooting

Implementing Single Sign-on

This guide will walk you through setting up single sign-on (SSO) between two web applications using FusionAuth as their common authentication and authorization server. You will use the hosted login pages for your login form.

These are the applications you’ll build:

  • Pied Piper

  • Hooli

At the end of this guide, both applications will be running. You can then log in to Pied Piper. Then if you visit Hooli, you will be automatically signed in to that second application. If you sign out from either of them, you’ll be signed out from both.

This pattern scales to any number of applications, and can include commercial off the shelf apps. If you have a suite of applications, you can provide a seamless single sign-on experience for all your users.

This guide illustrates a single sign-on scenario where FusionAuth is the system of record for your users.

If, instead, another datastore is your system of record, check out the Identity Providers documentation, which allows users to authenticate with third party login. This includes both social sign-on providers like Google as well as providers implementing standards such as OIDC.

Concepts

It’s worth spending a bit of time to discuss sessions. Sessions are how servers know they’ve seen the client, usually a browser, before. They are usually implemented with cookies, but the actual technologies used don’t matter. In the SSO scenario, the following sessions exist:

  • FusionAuth’s session, also known as the single sign-on session

  • The Pied Piper application’s session

  • The Hooli application’s session

If a session doesn’t exist for a given application, or expected values aren’t present in it, then the session must be created or updated after the user has presented valid credentials. For FusionAuth, the credentials are a username and password, but for the other applications, the credential is a valid FusionAuth token.

Request Flow Diagrams

Here’s the flow of a single sign-on login request.

Single sign-on request flow during login.
Single sign-on request flow during login.

Here’s the flow of the corresponding logout request.

Single sign-on request flow during logout.
Single sign-on request flow during logout.

Above, note that FusionAuth automatically logs the user out of the Hooli application after the user chooses to log out of the Pied Piper application. The user does not have to log out of multiple applications. The logout URLs will be called for each application in this tenant, allowing you to transparently sign the user out of three, five or ten web applications. However, you can disable this setting too.

Prerequisites

To walk through this guide, you will need to have FusionAuth and Node installed. For FusionAuth installation instructions, please visit the 5 minute setup guide.

Set Up The Domains

In order to properly exercise single sign-on, applications need to live on different domains, or at least different paths. If you, for instance, set up two Node applications at localhost:3000 and localhost:3001, browser sessions won’t be separated and the SSO functionality won’t work as intended. Cookies typically don’t differ based on ports, so you’ll see confusing behavior.

You can, however, easily set up two local domains. Edit your hosts file; on macOS, this file lives at /etc/hosts. Look for a line starting with 127.0.0.1, which is the address of your computer.

Add the following text to that line:

Additions to the /etc/hosts file
 hooli.local piedpiper.local

You want it to look something like this after editing:

The modified localhost line in /etc/hosts file
127.0.0.1       localhost hooli.local piedpiper.local

Later, when you have the code running, you can type http://piedpiper.local:3000 or http://hooli.local:3001 into your browser’s address bar and the local Node application will serve the request.

Configure The Applications In FusionAuth

Next, create and configure the applications in FusionAuth. You can do this via the API, but in this guide it’ll be accomplished through the administrative user interface.

Navigate to Applications and create two new applications. Configure the following for each application:

  • Name

  • Authorized redirect URL

  • Logout URL

The Name is used for display purposes.

The Authorized redirect URL lists all the valid redirect URLs that the application is capable of handling. In this case there is only one per application, but if you want your user to be sent to different landing pages based on where they signed in or some other parameter, you can add more.

Logout URL is where the user is sent if they log out from this application. It is also a URL requested by FusionAuth if you have multi-application logout enabled. The value of Logout behavior controls this. The default value of All applications means that when a user signs out of one FusionAuth application in a tenant, they are automatically signed out of all of them.

For the Pied Piper application, the configuration values will be:

  • Name: Pied Piper

  • Authorized redirect URL: http://piedpiper.local:3000/oauth-redirect

  • Logout URL: http://piedpiper.local:3000/endsession

For the Hooli application, the values will be:

  • Name: Hooli

  • Authorized redirect URL: http://hooli.local:3001/oauth-redirect

  • Logout URL: http://hooli.local:3001/endsession

All of these will be configured on the OAuth tab.

Here’s what the Pied Piper application might look like when properly configured:

Example of configured application.

Click "Save" for each application.

View each application by clicking the green magnifying glass when looking at the list of applications and note the Client Id and Client Secret values:

Looking up the Client Id and Client Secret values.

Set Up The User

You’ll need to make sure that a FusionAuth user is registered for both applications you created. You can use the default user created when installing FusionAuth or any other user. Here’s an example of what the user details of a user registered for both the Pied Piper and Hooli applications will look like:

Registering a user for both applications.

Set Up The Code

Next, set up the code. Both of the applications in this guide are written in Node, but the logic will be the same no matter the language. This code is available on GitHub, feel free to clone the repository.

Set up two Node applications, one for Pied Piper and one for Hooli. In this guide, the applications are very similar, so let’s create the Pied Piper application first. Once this is running, you can copy most of the code for the Hooli application.

First off, make a piedpiper directory and change into it.

Creating Pied Piper directory
mkdir piedpiper && cd piedpiper

Required packages

Set up your needed packages. Here’s what the package.json file should look like:

package.json
{
  "name": "fusionauth-node-example-sso-piedpiper",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "@fusionauth/typescript-client": "^1.22.0",
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "express-session": "1.17.0",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "pug": "2.0.0-beta11"
  }
}

Go ahead and install the needed modules:

Installing needed modules
npm install

The Express Server

This guide uses express for each application and the typescript client for interactions with the FusionAuth API. Create an app.js file; this is what will be executed when the server starts.

app.js
var createError = require('http-errors');
var cookieParser = require('cookie-parser');
var express = require('express');
var expressSession = require('express-session');
var path = require('path');
var logger = require('morgan');

var indexRouter = require('./routes/index');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(expressSession({resave: false, saveUninitialized: false, secret: 'fusionauth-node-example', cookie: {maxAge: 60000}}));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

That’s a lot of code, but most of it isn’t specific to these applications.

Let’s look at the parts that are:

app.js excerpts
//...
var indexRouter = require('./routes/index');

//...
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

//...
app.use(expressSession({resave: false,
                        saveUninitialized: false,
                        secret: 'fusionauth-node-example',
                        cookie: {maxAge: 60000}
                       }));
//...
app.use('/', indexRouter);
//...

indexRouter is set up and configured to read from the routes/index.js file. This app will use the pug view engine, configured with files from the views directory. The routes and views code will be built out in the next sections.

The session length for this application is 60 seconds; the maxAge value is in milliseconds. When the Node application’s session expires, it will redirect the end user to the FusionAuth application. If the single sign-on session has not expired, the user will be transparently redirected back. If it has expired, the user must re-authenticate.

As a last step, hook up indexRouter to the root path. Any request to this server will be handled by that router.

The www script

The next step is to create a script which starts up express. Place the contents of this file in bin/www.

bin/www
#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('fusionauth-node-example:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

This script is what running npm start actually executes.

This code isn’t that interesting with regards to single sign-on but is included for completeness.

It looks for a port from the environment or uses 3000 as the default. It also registers some error handling code. Then it starts up a server listening on that port, based on configuration from app.js.

Next, build out the indexRouter code referenced from the app.js file above.

The Index Route

Here’s the entire index.js file, which should be placed at routes/index.js:

routes/index.js
const express = require('express');
const router = express.Router();
const {FusionAuthClient} = require('@fusionauth/typescript-client');

const clientId = '85a03867-dccf-4882-adde-1a79aeec50df';
const clientSecret = '7gh9U0O1wshsrVVvflccX-UL2zxxsYccjdw8_rOfsfE';
const client = new FusionAuthClient('noapikeyneeded', 'http://localhost:9011');
const hostName = 'piedpiper.local';
const port = 3000;
const title = 'Pied Piper';

const loginUrl = 'http://localhost:9011/oauth2/authorize?client_id='+clientId+'&response_type=code&redirect_uri=http%3A%2F%2F'+hostName+'%3A'+port+'%2Foauth-redirect&scope=offline_access';
const logoutUrl = 'http://localhost:9011/oauth2/logout?client_id='+clientId;

/* GET home page. */
router.get('/', function (req, res, next) {

  if (!req.session.user) {
    res.redirect(302, loginUrl);
    return;
  }
  res.render('index', {user: req.session.user, title: title + ' App', clientId: clientId, logoutUrl: "/logout", loginUrl: loginUrl});
});

/* Login page if we aren't logged in */
router.get('/login', function (req, res, next) {
  res.render('login', {title: title + ' Login', clientId: clientId, loginUrl: loginUrl});
});

/* Logout page */
router.get('/logout', function (req, res, next) {
  req.session.user = null;
  res.redirect(302, logoutUrl);
});

/* End session for global SSO logout */
router.get('/endsession', function (req, res, next) {
  req.session.user = null;
  res.redirect(302, "/login");
});

/* OAuth return from FusionAuth */
router.get('/oauth-redirect', function (req, res, next) {
  // This code stores the user in a server-side session
  client.exchangeOAuthCodeForAccessToken(req.query.code,
                                         clientId,
                                         clientSecret,
                                         'http://'+hostName+':'+port+'/oauth-redirect')
      .then((response) => {
        return client.retrieveUserUsingJWT(response.response.access_token);
      })
      .then((response) => {
        if (response.response.user.registrations.length == 0 || (response.response.user.registrations.filter(reg => reg.applicationId === clientId)).length == 0) {
          console.log("User not registered, not authorized.");
          res.redirect(302, '/');
          return;
        }

        req.session.user = response.response.user;
      })
      .then((response) => {
        res.redirect(302, '/');
      }).catch((err) => {console.log("in error"); console.error(JSON.stringify(err));});
});

module.exports = router;

This code handles a number of paths. Let’s look at the code in more detail.

Constants section
const express = require('express');
const router = express.Router();
const {FusionAuthClient} = require('@fusionauth/typescript-client');

const clientId = '85a03867-dccf-4882-adde-1a79aeec50df';
const clientSecret = '7gh9U0O1wshsrVVvflccX-UL2zxxsYccjdw8_rOfsfE';
const client = new FusionAuthClient('noapikeyneeded', 'http://localhost:9011');
const hostName = 'piedpiper.local';
const title = 'Pied Piper';
const port = 3000;

const loginUrl = 'http://localhost:9011/oauth2/authorize?client_id='+clientId+'&response_type=code&redirect_uri=http%3A%2F%2F'+hostName+'%3A'+port+'%2Foauth-redirect&scope=offline_access';
const logoutUrl = 'http://localhost:9011/oauth2/logout?client_id='+clientId;

//...

The top of the index.js file has configuration values and some needed constants.

Update clientId and clientSecret variables with the values noted in the administrative user interface when you created the application in FusionAuth. You’ll also want to make sure that the second argument to the client constructor matches your FusionAuth installation, typically http://localhost:9011. If FusionAuth lives at a place other than that, change the loginUrl and loginUrl values as well.

The first argument is noapikeyneeded because the client interactions this application performs do not require an API key. If you extend these applications to update user data or make other privileged API calls, you’ll need to change that value to a real API key.

Home page route
//...

/* GET home page. */
router.get('/', function (req, res, next) {

  if (!req.session.user) {
    res.redirect(302, loginUrl);
    return;
  }
  res.render('index', {user: req.session.user, title: title +' App', clientId: clientId, logoutUrl: "/logout", loginUrl: loginUrl});
});
//...

In this SSO implementation, users can’t view the homepage if they aren’t signed in. This is a design choice you can make. The code checks for the presence of a user in the session and if it isn’t present, the user is redirected to the FusionAuth login page.

Login page route
//...
/* Login page if we aren't logged in */
router.get('/login', function (req, res, next) {
  res.render('login', {title: title +' Login', clientId: clientId, loginUrl: loginUrl});
});
//...

This page is available to users who are not logged in. For this guide, the only information on this page is a login link, but for a real application you’d probably want to entice the user to register or log in.

Logout page route
//...
/* Logout page */
router.get('/logout', function (req, res, next) {
  req.session.user = null;
  res.redirect(302, logoutUrl);
});
//...

This route removes the user object from the session and then redirects to the FusionAuth logout URL.

Recall that there are three sessions present in this system: the FusionAuth session and one for each Node application. This route invalidates the local node application’s session and then sends the browser to FusionAuth’s logout URL, which will invalidate both the FusionAuth session and all other Node application sessions.

Endsession route
//...
/* End session for global SSO logout */
router.get('/endsession', function (req, res, next) {
  req.session.user = null;
  res.redirect(302, "/login");
});
//...

This route is what FusionAuth requests when a user logs out from any other application in this tenant. If a user is in the Hooli application and logs out, they will be signed out from the Pied Piper application as well. You configured this endpoint in the FusionAuth application details; FusionAuth is responsible for calling this endpoint. This is a separate endpoint from the /logout endpoint because in this request, the browser needs to end up on a page accessible to unauthenticated users, but in the /logout case, the user needs to be sent to FusionAuth.

OAuth redirect route
//...
/* OAuth return from FusionAuth */
router.get('/oauth-redirect', function (req, res, next) {
  // This code stores the user in a server-side session
  client.exchangeOAuthCodeForAccessToken(req.query.code,
                                         clientId,
                                         clientSecret,
                                         'http://'+hostName+':'+port+'/oauth-redirect')
      .then((response) => {
        return client.retrieveUserUsingJWT(response.response.access_token);
      })
      .then((response) => {
        if (response.response.user.registrations.length == 0 || (response.response.user.registrations.filter(reg => reg.applicationId === clientId)).length == 0) {
          console.log("User not registered, not authorized.");
          res.redirect(302, '/');
          return;
        }

        req.session.user = response.response.user;
      })
      .then((response) => {
        res.redirect(302, '/');
      }).catch((err) => {console.log("in error"); console.error(JSON.stringify(err));});
});

module.exports = router;

This route is responsible for catching the authorization code request from FusionAuth after the user has signed in. It retrieves an access token and from that gathers the user data. This code ensures that the user is registered for this application, and then places the user data in the session.

Finally, export the router object for express to use. And that’s pretty much it for the Pied Piper application code.

Implementation of features that might cause a user to want to log in are left as an exercise for the reader.

Views

Next, create the views. Each of these live in the views subdirectory. First, the layout view, which looks like this:

Layout view
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    h2 Pied Piper |
       a(href='http://hooli.local:3001') Hooli
    block content

The content is displayed using the block content directive. Above it is a menu which lets users switch between both applications.

Login view
extends layout

block content
  h1= title
  a(href=loginUrl) Login

  p Welcome to #{title}

This is where you’d put information about your application for unauthorized users.

Index view
extends layout

block content
  h1= title

  p Hello #{user.firstName}
  a(href=logoutUrl) Log out

  p Welcome to #{title}

This welcomes the user by name.

There is some CSS in this application too; the CSS is available in the GitHub repository, but won’t be covered here.

Start It Up

Start the Pied Piper application on port 3000 after you’ve built the above files.

Starting up the Pied Piper application
PORT=3000 npm start

Next, create the sibling Hooli application.

Hooli application

In real life, these applications would have different functionality. For this guide, they are going to be similar. The only changes you need to make for the Hooli application are:

  • Put the same files in a directory called hooli.

  • Change index.js constants to use the Hooli values for the title (to 'Hooli'), hostname (hooli.local), port (3001), and the Client Id and Client Secret (from the admin UI application screen).

  • Change the layout so that the menu links to the Pied Piper application. Make sure to include the port.

Hooli layout view
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    h2
      a(href='http://piedpiper.local:3000') Pied Piper
      |
      || Hooli
    block content
  • Start the application on the port 3001. Use a different terminal window so that you can have both Node applications running at once.

Starting up the Hooli application
PORT=3001 npm start

And that’s it. You’ve just created a second application.

Test The Results

You can visit http://piedpiper.local:3000. You’ll be redirected to the FusionAuth login screen. Log in. You’ll be greeted with a welcome message by the Pied Piper app. Click on the 'Hooli' link and you’ll be automatically signed in to that application. You can log out as well.

Here’s a demo video of the single sign-on process from the end user perspective:

Caveat

If you are testing with Safari or Chrome on macOS, the multi application logout won’t work due to browser quirks. However, if you set up TLS and change the redirects to happen over https, then it will work. FireFox v83.0 works with either scenario.

Other Scenarios

In this guide users who click on the Hooli link are automatically logged in. This is appropriate for most applications. However, if you have an application but can’t customize the login process to check a session value and redirect if it doesn’t exist, you can still use SSO.

Instead of redirecting the user when there’s value is missing in such an application, display the FusionAuth login URL with the appropriate redirect parameter. The user will not be automatically signed in, but when they click on the login link, they will be sent to FusionAuth. FusionAuth will recognize the user as being signed in and redirect them back without requiring credentials.

COTS applications

If you are looking to integrate with a commercial off the shelf or open source software package, FusionAuth can act as a SAML identity provider or an OIDC OpenID Provider. For example, FusionAuth can act as an IdP for Zendesk, as shown in this video:

Please see the SAML IdP and OIDC documentation or the single sign-on documentation for the application you’re looking to integrate with for more.

Additional Configuration

Session Expiration

The single sign-on session duration can be configured at the Tenant level. Navigate to Tenant → Your Tenant → OAuth and edit the Session timeout value. Because this value is shared between applications, it can’t be overridden in application configuration.

Configuring the single sign-on session length.

The length of a single sign-on session can be different than the session length for individual applications. When a request to an application occurs, there are four possible scenarios:

Table 1. Single sign-on session scenarios
Application Session FusionAuth Session Result

valid

valid

Application serves request.

valid

expired

Application serves request.

expired

valid

Application redirects to FusionAuth, which redirects back to the application. The application then adds the user to the session and serves the request.

expired

expired

The user must authenticate with FusionAuth. On successful authentication, FusionAuth redirects back to the application. The application then adds the user to the session and serves the request.

Logout Behavior

The default behavior is to log a user out of all applications when they log out of one. If you want to only log the user out of the application where the user made the logout request, you can do that.

Navigate to Applications → Your Application → OAuth and configure Logout behavior to have the value Redirect Only.

Configuring the logout behavior for an application.

Additional Resources

You can view the example application’s codebase.

The Tenant API can be used to manage single sign-on related configuration.

This guide uses the hosted login pages. If you are using the Login API and building your own pages, check out the comments on this issue for guidance.

Feedback

How helpful was this page?

See a problem?

File an issue in our docs repo

Quick Links

  • Download
  • Cloud Pricing
  • Editions Pricing
  • Contact Us
  • Jobs (come work with us)
  • My Account

Resources

  • Docs
  • Blog
  • Community & Support
  • Upgrade from SaaS
  • Upgrade from Homegrown
  • Upgrade from Open Source

Everything Else

  • Privacy Policy
  • Product Privacy Policy
  • License
  • License FAQ
  • Enterprise Sales FAQ
  • Security (contact, bug bounty, etc)
  • Technical Support

Connect with Us

logo
Subscribe for Updates
We only send dev friendly newsletters. No marketing fluff!
© 2021 FusionAuth