FusionAuth developer image
FusionAuth developer logo
  • Back to site
  • Expert Advice
  • Blog
  • Developers
  • Downloads
  • Account
  • Contact sales
Navigate to...
  • Welcome
  • Getting Started
    • Getting Started
    • 5-minute Setup Guide
      • Overview
      • Docker
      • Fast Path
      • Sandbox
    • Setup Wizard & First Login
    • Register a User and Login
    • Self-service Registration
    • Start and Stop FusionAuth
    • Core Concepts
      • Overview
      • Users
      • Roles
      • Groups
      • Registrations
      • Applications
      • Tenants
      • Identity Providers
      • Authentication/Authorization
      • Integration Points
    • Example Apps
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • PHP
      • Python
      • Ruby
    • Tutorials
      • Overview
      • Java Spring
      • Python Django
  • Installation Guide
    • Overview
    • System Requirements
    • Server Layout
    • Cloud
    • Cluster
    • Docker
    • Fast Path
    • Kubernetes
      • Overview
      • Deployment Guide
      • Minikube Setup
      • Amazon EKS Setup
      • Google GKE Setup
      • Microsoft AKS Setup
    • Kickstart™
    • Homebrew
    • Marketplaces
    • Packages
    • Database
    • FusionAuth App
    • FusionAuth Search
    • Common Configuration
  • Migration Guide
    • Overview
    • General
    • Auth0
    • Keycloak
    • Amazon Cognito
    • Firebase
    • Microsoft Azure AD B2C
    • Tutorial
  • Admin Guide
    • Overview
    • Account Portal
    • Config Management
    • Editions and Features
    • Key Rotation
    • Licensing
    • Monitoring
    • Prometheus Setup
    • Proxy Setup
    • Reference
      • Overview
      • Configuration
      • CORS
      • Data Types
      • Hosted Login Pages Cookies
      • Known Limitations
      • Password Hashes
    • Releases
    • Roadmap
    • Search And FusionAuth
    • Securing
    • Switch Search Engines
    • Technical Support
    • Troubleshooting
    • Upgrading
    • WebAuthn
  • Login Methods
    • Identity Providers
      • Overview
      • Apple
      • Epic Games
      • External JWT
        • Overview
        • Example
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
        • Overview
        • Amazon Cognito
        • Azure AD
        • Discord
        • Github
        • Okta
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • SAML v2
        • Overview
        • ADFS
        • Azure AD
        • Okta
      • SAML v2 IdP Initiated
        • Overview
        • Okta
      • Xbox
    • OIDC & OAuth 2.0
      • Overview
      • Endpoints
      • Tokens
      • OAuth Modes
      • URL Validation
    • Passwordless
      • Overview
      • Magic Links
      • WebAuthn & Passkeys
    • SAML v2 IdP
      • Overview
      • Google
      • PagerDuty
      • Tableau Cloud
      • Zendesk
  • Developer Guide
    • Overview
    • API Gateways
      • Overview
      • Amazon API Gateway
      • Kong Gateway
      • ngrok Cloud Edge
    • Client Libraries & SDKs
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • Node
      • OpenAPI
      • PHP
      • Python
      • React
      • Ruby
      • Typescript
    • Events & Webhooks
      • Overview
      • Writing a Webhook
      • Securing Webhooks
      • Events
        • Overview
        • Audit Log Create
        • Event Log Create
        • JWT Public Key Update
        • JWT Refresh
        • JWT Refresh Token Revoke
        • Kickstart Success
        • Group Create
        • Group Create Complete
        • Group Delete
        • Group Delete Complete
        • Group Update
        • Group Update Complete
        • Group Member Add
        • Group Member Add Complete
        • Group Member Remove
        • Group Member Remove Complete
        • Group Member Update
        • Group Member Update Complete
        • User Action
        • User Bulk Create
        • User Create
        • User Create Complete
        • User Deactivate
        • User Delete
        • User Delete Complete
        • User Email Update
        • User Email Verified
        • User IdP Link
        • User IdP Unlink
        • User Login Failed
        • User Login Id Dup. Create
        • User Login Id Dup. Update
        • User Login New Device
        • User Login Success
        • User Login Suspicious
        • User Password Breach
        • User Password Reset Send
        • User Password Reset Start
        • User Password Reset Success
        • User Password Update
        • User Reactivate
        • User Reg. Create
        • User Reg. Create Complete
        • User Reg. Delete
        • User Reg. Delete Complete
        • User Registration Update
        • User Reg. Update Complete
        • User Reg. Verified
        • User 2FA Method Add
        • User 2FA Method Remove
        • User Update
        • User Update Complete
    • Guides
      • Overview
      • Application Specific Email Templates
      • Authentication Tokens
      • Exposing A Local Instance
      • JSON Web Tokens
      • Key Master
      • Localization and Internationalization
      • Multi-Factor Authentication
      • Multi-Tenant
      • Passwordless
      • Registration-based Email Verification
      • Searching With Elasticsearch
      • Securing Your APIs
      • Silent Mode
      • Single Sign-on
      • Two Factor (pre 1.26)
    • Integrations
      • Overview
      • CleanSpeak
      • Kafka
      • Twilio
    • Plugins
      • Overview
      • Writing a Plugin
      • Custom Password Hashing
    • User Control & Gating
      • Overview
      • Gate Unverified Users
      • Gate Unverified Registrations
      • User Account Lockout
  • Customization
    • Email & Templates
      • Overview
      • Configure Email
      • Email Templates
      • Email Variables
      • Message Templates
    • Lambdas
      • Overview
      • Apple Reconcile
      • Client Cred. JWT Populate
      • Epic Games Reconcile
      • External JWT Reconcile
      • Facebook Reconcile
      • Google Reconcile
      • HYPR Reconcile
      • JWT Populate
      • LDAP Connector Reconcile
      • LinkedIn Reconcile
      • Nintendo Reconcile
      • OpenID Connect Reconcile
      • SAML v2 Populate
      • SAML v2 Reconcile
      • SCIM Group Req. Converter
      • SCIM Group Resp. Convtr.
      • SCIM User Req. Converter
      • SCIM User Resp. Converter
      • Self-Service Registration
      • Sony PSN Reconcile
      • Steam Reconcile
      • Twitch Reconcile
      • Twitter Reconcile
      • Xbox Reconcile
    • Messengers
      • Overview
      • Generic Messenger
      • Twilio Messenger
    • Themes
      • Overview
      • Examples
      • Helpers
      • Localization
      • Template Variables
      • Kickstart Custom Theme
  • Premium Features
    • Overview
    • Advanced Registration Forms
    • Advanced Threat Detection
    • Application Specific Themes
    • Breached Password Detection
    • Connectors
      • Overview
      • Generic Connector
      • LDAP Connector
      • FusionAuth Connector
    • Entity Management
    • SCIM
      • Overview
      • Azure AD Client
      • Okta Client
      • SCIM-SDK
    • Self Service Account Mgmt
      • Overview
      • Updating User Data & Password
      • Add Two-Factor Authenticator
      • Add Two-Factor Email
      • Add Two-Factor SMS
      • Add WebAuthn Passkey
      • Customizing
      • Troubleshooting
    • WebAuthn
  • APIs
    • Overview
    • Authentication
    • Errors
    • API Explorer
    • Actioning Users
    • API Keys
    • Applications
    • Audit Logs
    • Connectors
      • Overview
      • Generic
      • LDAP
    • Consents
    • Emails
    • Entity Management
      • Overview
      • Entities
      • Entity Types
      • Grants
    • Event Logs
    • Families
    • Forms
    • Form Fields
    • Groups
    • Identity Providers
      • Overview
      • Links
      • Apple
      • External JWT
      • Epic Games
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
      • SAML v2
      • SAML v2 IdP Initiated
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • Xbox
    • Integrations
    • IP Access Control Lists
    • JWT
    • Keys
    • Lambdas
    • Login
    • Message Templates
    • Messengers
      • Overview
      • Generic
      • Twilio
    • Multi-Factor/Two Factor
    • Passwordless
    • Reactor
    • Registrations
    • Reports
    • SCIM
      • Overview
      • SCIM User
      • SCIM Group
      • SCIM EnterpriseUser
      • SCIM Service Provider Config.
    • System
    • Tenants
    • Themes
    • Users
    • User Actions
    • User Action Reasons
    • User Comments
    • WebAuthn
    • Webhooks
  • Release Notes

    Fast Path Install For the 5-Minute Guide

    You’ve chosen to install FusionAuth via Fast Path, using a local database (PostgreSQL or MySQL).

    This is the best option if you have a local database already set up or you want to test FusionAuth with an external database.

    If you’ve arrived here directly, start with the 5-Minute Setup Guide Overview.

    Requirements

    You need to have Node.js installed. This document has been tested with version 14 and 18, but should work with other versions.

    Testing the Node.js Installation
    
    node -v
    Result Of Testing the Node.js Installation
    
    v18.10.0

    You need to have either a MySQL or PostgreSQL database installed. You also need a superuser name and password for the database; this user needs to be able to create schemas and databases.

    If you do not have a database installed, follow the instructions in our Database Installation Guide to install a database. Below, you see commands to test if the PostgreSQL command line tool, psql, is present.

    Testing the Postgresql Installation
    
    psql --version
    Result Of Testing the Postgresql Installation
    
    psql (PostgreSQL) 12.3

    Overview

    Here are steps to take to set up FusionAuth and configure it to provide login and logout functionality for your application.

    1. Install FusionAuth

    2. Start FusionAuth

    3. Complete Maintenance Mode

    4. Complete the Setup Wizard

    5. Create an Application and configure the OAuth settings

    6. Grant Permissions

    7. Configure the Backend to Complete the Login

    8. Store the user object in the session

    9. Test the Application

    10. Logout

    11. Summing Up

    Steps similar to these will be used for integrating with any identity provider. Let’s get into the details of each step.

    1. Install FusionAuth

    You are following the FastPath installation guide, so you’ll use the FastPath method to install FusionAuth.

    macOS

    Please feel free to read these install scripts before running them. Always a good idea.

    Install in your current working directory using ZIP packages
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh"
    Install in your current working directory using ZIP packages and include Elasticsearch
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh -s - -s"

    Linux

    Please feel free to read these install scripts before running them. Always a good idea.

    Install in your current working directory using ZIP packages
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh -s - -z"
    Install in your current working directory using ZIP packages and include Elasticsearch
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh -s - -z -s"
    Install for all users on the system using DEB or RPM packages, requires sudo access
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh"
    Install for all users on the system using DEB or RPM packages and include Elasticsearch, requires sudo access
    
    sh -c "curl -fsSL https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.sh | sh -s - -s"

    Windows

    Please note, that versions equal to 1.37.0 and less than 1.40.0 did not have a native Windows install option. It is recommended to plan to install version 1.40.0 or later.

    Please feel free to read these install scripts before running them. Always a good idea.

    Install in your current working directory using ZIP packages. Install using Windows PowerShell
    
    . { iwr -useb https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.ps1 } | iex; install
    Install in your current working directory using ZIP packages and include Elasticsearch. Install using Windows PowerShell
    
    . { iwr -useb https://raw.githubusercontent.com/FusionAuth/fusionauth-install/master/install.ps1 } | iex; install -includeSearch 1

    Once the Fast Path installer completes, you will see the below output.

    Fast Path Install Complete
    
    Downloading zip packages
    ######################################################################## 100.0%
    ######################################################################## 100.0%
    Installing packages
    
    Install is complete. Time for tacos.
    
     1. To start FusionAuth run the following command
        /Users/bpontarelli/dev/example/fusionauth/bin/startup.sh
    
     2. To begin, access FusionAuth by opening a browser to http://localhost:9011
    
     3. If you're looking for documentation, open your browser and navigate to https://fusionauth.io/docs
    
    Thank you have a nice day.

    Don’t forget to enjoy the tacos.

    2. Start FusionAuth

    The next step is to start FusionAuth using the command that the Fast Path installer created. This script is called startup.sh or startup.ps1. You can execute it from the installation directory.

    MacOS and Linux Startup Script
    
    fusionauth/bin/startup.sh

    If you are on Windows, you’ll need to use the startup.ps1. Prior to version 1.40.0 the file will be named startup.bat instead.

    Windows Startup Script
    
    .\fusionauth\bin\startup.ps1

    This script will start both the fusionauth-app component as well as the fusionauth-search component if you downloaded the Elasticsearch option. (Here’s a document on how to choose whether to do so.)

    3. Complete Maintenance Mode

    After you have FusionAuth installed and running, open your browser to http://localhost:9011. This is the default address for FusionAuth when running locally. This will bring up the FusionAuth admin UI, which should be sitting in Maintenance Mode and ready to be configured.

    FusionAuth enters Maintenance Mode any time the database is not accessible or is not properly set up. In this case, FusionAuth was able to connect, but the system was not configured. Below is a screenshot of the Maintenance Mode screen.

    Maintenance Mode Database

    Here you need to provide the super user credentials for the database along with the database hostname, if it isn’t running locally. You can also select either MySQL or PostgreSQL and change the database port if needed. For this example, you will be using PostgreSQL on the standard port with a super username of postgres and a password of password. You can also change the username and password that will be created as the primary database account that FusionAuth will access. This is the fusionauth user above, but can be set to any username and password you desire.

    The reason that FusionAuth uses a separate username and password to connect to the database during normal operation is that if the configuration is compromised and an attacker learns the database username and password, they will only have access to the FusionAuth database. This is helpful if you are using a single database server for multiple applications and databases. This is known as the principle of least privilege and FusionAuth generally follows this principle.

    Once you click the Submit button, you will be taken to the next step of Maintenance Mode. If you have opted to install with Elasticsearch, this step is where the FusionAuth Search component is configured, otherwise you can skip ahead to step 4, the Setup Wizard.

    Our Fast Path install and startup script automatically start the fusionauth-search component, which is a standard version of Elasticsearch. Since FusionAuth is able to connect to this search engine, all that is needed is to create the indexes inside it. This page looks like this.

    Maintenance Mode Search

    Clicking the Submit button here will cause FusionAuth to exit Maintenance Mode and begin starting up. You see an interstitial page.

    Interstitial

    4. Complete the Setup Wizard

    Once FusionAuth starts up successfully, you will be taken to the Setup Wizard. This is where you will create the administrator account for FusionAuth and accept the license.

    Record the email and password you choose for the administrator account. You won’t be able to recover this without setting up an email server, which is beyond the scope of this tutorial.

    You can also sign up for the FusionAuth newsletter, which is a great way to stay up-to-date on FusionAuth releases and new features. We will never pitch you, hard-sell or sell your information, so feel free to sign up.

    Here’s what the Setup Wizard page looks like.

    Setup Wizard

    Clicking Submit here will complete the Setup Wizard and log you into the FusionAuth administrative user interface.

    5. Create an Application and Configure the OAuth settings

    Once you arrive in the FusionAuth admin UI, the first thing you need to do is create an Application. An Application is something that a user can log into. This is the application you are building or that you are migrating to use FusionAuth. Click the Application menu option on the left side of the page or the Setup button in the box at the top of the page.

    Dashboard to Applications

    This will take you to the listing page for Applications. Next, you’ll click the green plus button (the add button) at the top of the page:

    Application Listing

    On the Application form, provide a name for your Application (this is only used for display purposes) and a couple of items on the OAuth tab. Start with a simple setup that allows existing users to log into your application. There is no need to add any roles or registration configuration.

    When you click on the OAuth tab, you’ll see this form.

    Application Form

    Most of the defaults will work, but provide the following items.

    • An authorized redirect URL. This is the route/controller in your application’s backend that will complete the OAuth grant and obtain a token. For this example, add http://localhost:3000/oauth-redirect. You will see example code below for this route.

    • Specify a valid Logout URL. This is where the user will be redirected to after they are logged out of FusionAuth’s OAuth front-end: your application. For this example, set this value to http://localhost:3000/logout. You’ll see how this is used below.

    • Make sure the Authorization Code grant is selected in the Enabled Grants.

    • Set the Require registration field to true.

    Once you have configured the application, you’ll click the blue "Save" button at the top of the page.

    Save Button Application Form

    Then, click on the green magnifying glass on the list view next to your application. Scroll down to the OAuth Configuration section and copy the Client Id and Client Secret values off to a text file. You’ll use them later.

    Application Details

    6. Grant Permissions

    Next, grant the user you created in the Setup Wizard permissions to log into your new Application. This can be done from the User management section of the FusionAuth admin UI. Click the Users link in the navigation. If needed, search for the user.

    Manage the user’s details by clicking on the black "Manage" button.

    User Search

    Once you are in this user’s account, you’ll click the "Add Registration" button. This will take us to a page that will allow us to add a registration for this user to the new Application. Registrations associate users with applications. You may have to select an Application if there are multiple options.

    Registration Add Form

    For this tutorial, you don’t need to provide any additional information for the registration; click the save button at the top.

    Now the user has permissions to log into your application.

    Adding a registration to a user is not always required to let your users log in to your application.

    FusionAuth supports self-service registration. With self-service registration enabled, a registration will be added when a user signs up. Learn more about self-service registration.

    You want to make sure your user account has a first name, which should appear under the picture.

    If they don’t, use the Edit Profile button in the upper right hand corner of the user details screen to edit the account account and give them one. The first name is how they’ll be greeted in the application.

    7. Configure the Backend to Complete the Login

    Before you test the login, examine the route/controller in your application’s backend that will complete the OAuth workflow.

    After a user logs into FusionAuth’s OAuth front-end successfully, their browser will be redirected to the URL you provided in the configuration step above. This redirect will contain a query parameter called code that contains the one-time use OAuth authorization code from FusionAuth.

    Your application code provides the code parameter in a request to FusionAuth. It will exchange the code for an access token, which can be used for a variety of purposes.

    In order to complete the process, you’ll use a sample application, which uses the FusionAuth typescript client library, Express and Pug templates. This code is available for download.

    To get started, clone the project, and navigate to the project directory.

    Get the Example Application Code
    
    git clone https://github.com/FusionAuth/fusionauth-example-5-minute-guide \
    && cd fusionauth-example-5-minute-guide

    Here’s a sample .env file, which includes some configuration you’ll need to change.

    The Contents Of the .env.sample File
    
    CLIENT_ID=CHANGEME
    CLIENT_SECRET=CHANGEME
    BASE_URL=http://localhost:9011
    Copy .env.sample To .env
    
    cp .env.sample .env

    Edit the .env file and update the CLIENT_ID and CLIENT_SECRET values. Set them to the Client Id and the Client Secret you noted when examining the application configuration in a previous step.

    If you are not running locally, change the BASE_URL to the correct value.

    That’s all the changes you need to make to the .env file.

    Next, here’s the package.json file, which includes all the components you’ll need.

    The Contents Of the package.json File
    
    {
      "name": "fusionauth-example-5-minute-guide",
      "version": "1.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",
        "dotenv": "^16.0.3",
        "express": "^4.18.2",
        "express-session": "1.17.0",
        "http-errors": "~1.6.3",
        "morgan": "~1.9.1",
        "pkce-challenge": "^2.1.0",
        "pug": "3.0.1"
      }
    }

    Install required packages using npm.

    Install Required Packages
    
    npm install

    This application is almost ready to run, but let’s look at some code first. Here’s the heart of the application, the main Express router.

    The Node.js Complete Express Router
    
    const express = require('express');
    const router = express.Router();
    const {FusionAuthClient} = require('@fusionauth/typescript-client');
    
    // tag::clientIdSecret[]
    // set in the environment or directly
    const clientId = process.env.CLIENT_ID; // or set directly
    const clientSecret = process.env.CLIENT_SECRET; // or set directly
    // end::clientIdSecret[]
    
    // tag::baseURL[]
    const fusionAuthURL = process.env.BASE_URL;
    // end::baseURL[]
    
    const client = new FusionAuthClient('noapikeyneeded', fusionAuthURL);
    const pkceChallenge = require('pkce-challenge');
    
    // tag::logoutRoute[]
    /* logout page. */
    router.get('/logout', function (req, res, next) {
      req.session.destroy();
      res.redirect(302, '/');
    });
    // end::logoutRoute[]
    
    /* GET home page. */
    router.get('/', function (req, res, next) {
      const stateValue = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
      req.session.stateValue = stateValue;
    
      //generate the pkce challenge/verifier dict
      const pkce_pair = pkceChallenge();
      // Store the PKCE verifier in session
      req.session.verifier = pkce_pair['code_verifier'];
      const challenge = pkce_pair['code_challenge'];
      res.render('index', {user: req.session.user, title: 'FusionAuth Example', clientId: clientId, challenge: challenge, stateValue: stateValue, fusionAuthURL: fusionAuthURL});
    });
    
    // tag::fullOAuthCodeExchange[]
    /* OAuth return from FusionAuth */
    router.get('/oauth-redirect', function (req, res, next) {
      const stateFromServer = req.query.state;
      if (stateFromServer !== req.session.stateValue) {
        console.log("State doesn't match. uh-oh.");
        console.log("Saw: " + stateFromServer + ", but expected: " + req.session.stateValue);
        res.redirect(302, '/');
        return;
      }
    
    // tag::exchangeOAuthCode[]
      // This code stores the user in a server-side session
     client.exchangeOAuthCodeForAccessTokenUsingPKCE(req.query.code,
                                                     clientId,
                                                     clientSecret,
                                                     'http://localhost:3000/oauth-redirect',
                                                     req.session.verifier)
    // end::exchangeOAuthCode[]
          .then((response) => {
            console.log(response.response.access_token);
            return client.retrieveUserUsingJWT(response.response.access_token);
          })
          .then((response) => {
    // tag::setUserInSession[]
            req.session.user = response.response.user;
            return response;
          })
    // end::setUserInSession[]
          .then((response) => {
            res.redirect(302, '/');
          }).catch((err) => {console.log("in error"); console.error(JSON.stringify(err));});
    
    });
    // end::fullOAuthCodeExchange[]
    
      // This code can be set in the last promise above to send the access and refresh tokens
      // back to the browser as secure, HTTP-only cookies, an alternative to storing user info in the session
      //     .then((response) => {
      //       res.cookie('access_token', response.response.access_token, {httpOnly: true});
      //       res.cookie('refresh_token', response.response.refresh_token, {httpOnly: true});
      //       res.redirect(302, '/');
      //     }).catch((err) => {console.log("in error"); console.error(JSON.stringify(err));});
    
    module.exports = router;

    There are three main routes:

    • /logout, which logs the user out by destroying the local session

    • /, which is the home page

    • /oauth-redirect which handles the results of the login at FusionAuth and completes the grant, as mentioned above. After the token is retrieved, the user is stored in the session. This will be discussed further below.

    There are also files under the views directory, which are the views shown to the end user.

    8. Store the User Object In The Session

    There is a route that corresponds to the URL you configured in the FusionAuth admin user interface above (https://localhost:3000/oauth-redirect). This is critical functionality, so let’s take a closer look at this.

    Here’s the complete code for exchanging the token, retrieving the user data, storing it in the session, and redirecting the user.

    The Complete OAuth Code Exchange Function
    
    //...
    /* OAuth return from FusionAuth */
    router.get('/oauth-redirect', function (req, res, next) {
      const stateFromServer = req.query.state;
      if (stateFromServer !== req.session.stateValue) {
        console.log("State doesn't match. uh-oh.");
        console.log("Saw: " + stateFromServer + ", but expected: " + req.session.stateValue);
        res.redirect(302, '/');
        return;
      }
    
      // This code stores the user in a server-side session
     client.exchangeOAuthCodeForAccessTokenUsingPKCE(req.query.code,
                                                     clientId,
                                                     clientSecret,
                                                     'http://localhost:3000/oauth-redirect',
                                                     req.session.verifier)
          .then((response) => {
            console.log(response.response.access_token);
            return client.retrieveUserUsingJWT(response.response.access_token);
          })
          .then((response) => {
            req.session.user = response.response.user;
            return response;
          })
          .then((response) => {
            res.redirect(302, '/');
          }).catch((err) => {console.log("in error"); console.error(JSON.stringify(err));});
    
    });
    //...

    This route retrieves the code parameter from the request and exchanges it for an access token. This access token can be used for a variety of purposes, but in this tutorial is used to retrieve user data from FusionAuth.

    Once you have the User object, it is stored in a server side session so that it can be used in other parts of the application. This includes a view where it is used to greet the user.

    There are other options for storing this user object, but for this tutorial, this will work fine. If you want to learn more, such as other patterns for storing the token, please check out these articles about login workflows.

    The final thing this code does is redirect the authorized user back to the homepage. There, they’ll be greeted by name, as you’ll see below.

    9. Test the Application

    Now that everything is written, let’s test the workflow. Fire up the Node.js application using this command.

    Start the Node.js Server
    
    npm start

    Open http://localhost:3000/ in an incognito browser.

    You need to use an incognito browser because otherwise FusionAuth won’t prompt you to login. You have already logged into FusionAuth when you configured the application above, and will be recognized.

    FusionAuth supports single sign-on, and will automatically redirect you to the application if you are already logged in with the FusionAuth server.

    The Node.js Application Home Screen

    Click the Login link, this will take us to FusionAuth’s login page.

    The Login Screen

    From here, you can log in with the account you used to access the admin user interface above. If you log in with a valid account that is registered for the application, you arrive at the home page, but are greeted by name.

    Successful Login

    In a real application, there’d be a lot more than a "Hello" message, but this is a building block. You’ve successfully authenticated and stored user data in the express session. From here, you can add other pages, hide or display information based on attributes of the user, and more.

    If, on the other hand, you log in with an account that exists in FusionAuth but is not registered for the application, you’ll end up at an error page.

    Login Without Registration

    This error message and overall page look and feel can be modified via a custom FusionAuth theme.

    10. Logout

    Of course, for every login, there should be a corresponding logout. Log out by clicking on the "Logout" link. This will log you out of both FusionAuth and the application.

    Here’s the pug code which builds a link to log the user out.

    The Logout Link
    
    //...
        a(href=fusionAuthURL+'/oauth2/logout/?client_id='+clientId) Logout
    //...

    When you visit this link, you’re sent to FusionAuth, where the FusionAuth session is destroyed, and then to the application’s logout URL. This URL was configured when you set up the Application in FusionAuth, and has the value of http://localhost:3000/logout.

    That route destroys the local session, logging you out from the Node.js application, and then sending you back to the home page.

    Destroying the Local Session
    
    //...
    /* logout page. */
    router.get('/logout', function (req, res, next) {
      req.session.destroy();
      res.redirect(302, '/');
    });
    //...

    Now you are logged out.

    11. Summing Up

    You’ve now taken an application and layered on authentication with FusionAuth. A user who is registered for the application can log in, view private data, and log out.

    Congrats!

    Here are typical next steps.

    • setting up self-service registration so you don’t need to add every user via the admin UI

    • configuring the theme to make the FusionAuth pages look like your application

    • looking at tutorials in other programming languages

    • read about FusionAuth core concepts like Tenants and Roles

    • researching what kind of login workflow fits your needs

    Of course, there are plenty of other docs, covering a variety of topics. Here are some popular ones.

    • Customizing JWTs

    • Sending and customizing emails

    • Logging in with OIDC, SAML and social login providers like Google

    • Setting Up MFA/Two-Factor

    • Supported OAuth grants

    • Single sign-on aka SSO

    • Managing user data with the User API

    • Premium features

    Feedback

    Thanks for completing the 5 minute guide. What topics would you want to learn next? Please choose three at most.

    Feedback

    How helpful was this page?

    See a problem?

    File an issue in our docs repo

    Have a question or comment to share?

    Visit the FusionAuth community forum.

    © 2023 FusionAuth
    How-to
    Subscribe for developer updates