diff --git a/astro/src/content/articles/authentication/multi-factor-authentication.md b/astro/src/content/articles/authentication/multi-factor-authentication.md index ed9df79e70..db93d10cf2 100644 --- a/astro/src/content/articles/authentication/multi-factor-authentication.md +++ b/astro/src/content/articles/authentication/multi-factor-authentication.md @@ -1,6 +1,6 @@ --- -title: "Multi-Factor Authentication (MFA): The Ultimate Guide" -description: What is multi-factor authentication and how it works? +title: "What is Multi-Factor Authentication (MFA) and How it Works" +description: Learn what MFA is, why it's crucial, the available factors, and when to consider requiring multi-factor authentication for enhanced security. author: Dan Moore section: Authentication tags: mfa 2fa multi-factor-authentication two-factor-authentication user-experience customer-experience security policie sms totp factors ap-push tradeoffs open-standards biometric diff --git a/astro/src/content/articles/identity-basics/magic-links.md b/astro/src/content/articles/identity-basics/magic-links.md index 7ab4b4c40f..758d52dbd6 100644 --- a/astro/src/content/articles/identity-basics/magic-links.md +++ b/astro/src/content/articles/identity-basics/magic-links.md @@ -1,6 +1,6 @@ --- -title: What are Magic Links and How to Use Them -description: "Magic Links: A Guide to Passwordless Authentication" +title: Magic Links - A Guide to Passwordless Authentication +description: "Magic links offer secure, passwordless authentication, enhancing user experience and security. Learn more in and improve your access control today!" author: Brad McCarty icon: /img/icons/magic-links.svg darkIcon: /img/icons/magic-links-dark.svg diff --git a/astro/src/content/articles/identity-basics/what-is-oidc.mdx b/astro/src/content/articles/identity-basics/what-is-oidc.mdx index 7ac9ba6a9c..ce173c4a6f 100644 --- a/astro/src/content/articles/identity-basics/what-is-oidc.mdx +++ b/astro/src/content/articles/identity-basics/what-is-oidc.mdx @@ -1,6 +1,6 @@ --- -title: "What Is OpenID Connect (OIDC)?" -description: "What Is OpenID Connect (OIDC) and How It Works" +title: "What Is OpenID Connect (OIDC) and How It Works" +description: "Explore OpenID Connect (OIDC) and understand how it enhances authentication for web and mobile applications. Learn its workings, benefits, and more." author: Dan Moore icon: /img/icons/what-is-oidc.svg darkIcon: /img/icons/what-is-oidc-dark.svg diff --git a/astro/src/content/articles/oauth/modern-guide-to-oauth.mdx b/astro/src/content/articles/oauth/modern-guide-to-oauth.mdx index 8bbd95adef..3842c4c480 100644 --- a/astro/src/content/articles/oauth/modern-guide-to-oauth.mdx +++ b/astro/src/content/articles/oauth/modern-guide-to-oauth.mdx @@ -1,6 +1,6 @@ --- -title: Modern Guide - What is OAuth 2.0 and How Does It Work? -description: What is OAuth 2.0 and How does it Work? +title: What is OAuth 2.0 and How does it Work? +description: Discover what OAuth 2.0 is, how it works, and its importance in securing and managing access to online resources. Learn about its key grants and benefits. image: advice/modern-guide-oauth/expert-advice-the-modern-guide-to-oauth-header-image.png author: Brian Pontarelli, Ahmed Hashesh and Dan Moore section: OAuth diff --git a/astro/src/content/docs/lifecycle/authenticate-users/identity-providers/index.mdx b/astro/src/content/docs/lifecycle/authenticate-users/identity-providers/index.mdx index f188cb761c..e232c9149e 100644 --- a/astro/src/content/docs/lifecycle/authenticate-users/identity-providers/index.mdx +++ b/astro/src/content/docs/lifecycle/authenticate-users/identity-providers/index.mdx @@ -9,6 +9,7 @@ topOfNav: true --- import Aside from 'src/components/Aside.astro'; import InlineField from 'src/components/InlineField.astro'; +import InlineUIElement from 'src/components/InlineUIElement.astro'; import ScrollRef from 'src/components/ScrollRef.astro'; import { YouTube } from '@astro-community/astro-embed-youtube'; import IdentityProviderLimitations from 'src/content/docs/_shared/_identity-provider-limits.mdx'; @@ -79,13 +80,21 @@ When you enable an identity provider you're indicating that this external provid ## Overrides -For each application, you can provide different identity provider configurations. You might do this if you had two different applications that were both using Apple as an identity provider, but with different Apple configuration settings. You can override none, some or all of the configuration values by expanding the "Overrides" link for the given application assignment or modifying the identityProvider.applicationConfiguration values using the API. +You can have different identity provider configurations for different applications. Suppose you had two different applications that were both using the Apple Identity Provider. But for one, you wanted to request the `email name` scope and for the other you wanted to request the `email` scope only. To make this work, create the Apple Identity provider with the scope `email name` and assign it to the first application. Then, for the second, override the Scope field with the `email` value. + +You can override none, some or all of the available configuration values by expanding the Overrides element for the application's identity provider setting. You may also modify the identityProvider.applicationConfiguration values using the API. Overriding Identity Provider settings -However, you cannot have two different Identity Providers for the same application. Use two different applications instead. +For certain Identity Providers, there are no override settings since you can create more than one. You can have multiple configurations for these Identity Provider types: + +* External JWT +* SAMLv2 +* OpenID Connect/OIDC + +For other Identity Providers, such as Apple, Google or Facebook, you cannot have two different Identity Providers of the same type assigned to the same Application. Use overrides as documented above. -Additionally, override settings are not available in the External JWT, SAMLv2, or OpenID Connect Identity Providers. You can create multiple instances of these providers; that is the correct way to have multiple configurations for these providers +In some cases, you need to use two different Applications to achieve your desired configuration. For example, if you need two sets of attributes for an Identity Provider, but the attributes don't exist in the Overrides options. An example of such an attribute is Linking Strategy. ## Hints diff --git a/astro/src/content/docs/lifecycle/authenticate-users/single-sign-on.mdx b/astro/src/content/docs/lifecycle/authenticate-users/single-sign-on.mdx index 32937a2593..7e46a41d4d 100644 --- a/astro/src/content/docs/lifecycle/authenticate-users/single-sign-on.mdx +++ b/astro/src/content/docs/lifecycle/authenticate-users/single-sign-on.mdx @@ -4,14 +4,17 @@ description: Learn how to implement single sign-on between applications using Fu navcategory: developer section: lifecycle subcategory: authenticate users +codeRoot: https://raw.githubusercontent.com/FusionAuth/fusionauth-example-node-sso/main --- import Aside from 'src/components/Aside.astro'; import InlineField from 'src/components/InlineField.astro'; import Breadcrumb from 'src/components/Breadcrumb.astro'; +import InlineUIElement from 'src/components/InlineUIElement.astro'; import LogoutBehaviorAllApplications from 'src/content/docs/get-started/core-concepts/_logout-behavior-all-applications.mdx'; import SSOLogin from 'src/diagrams/docs/lifecycle/authenticate-users/sso-login.astro'; import SSOLogout from 'src/diagrams/docs/lifecycle/authenticate-users/sso-logout.astro'; import { YouTube } from '@astro-community/astro-embed-youtube'; +import {RemoteCode} from '@fusionauth/astro-components'; 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. @@ -128,36 +131,20 @@ Next, set up the code. Both of the applications in this guide are written in Nod 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. +First off, make a `pied-piper` directory and change into it. ```shell script title="Creating Pied Piper directory" -mkdir piedpiper && cd piedpiper +mkdir pied-piper && cd pied-piper ``` ### Required packages Set up your needed packages. Here's what the `package.json` file should look like: -```json title="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: @@ -169,183 +156,40 @@ npm install This guide uses express for each application and the [typescript client](/docs/sdks/typescript) for interactions with the FusionAuth API. Create an `app.js` file; this is what will be executed when the server starts. -```javascript title="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: - -```javascript title="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); -//... -``` +This is a pretty standard express application which uses pug and sessions. It reads routes from files in the `routes` directory and views from the `views` directory. -`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 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 FusionAuth. 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. ### The `www` script The next step is to create a script which starts up express. Place the contents of this file in `bin/www`. -```javascript title="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`. +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`.' + +### The .env File + +Here's the `.env` file, which should be placed at `.env`: + + +This contains configuration settings such as the Client Id and Client Secret. Make sure to update it with the correct values you've copied in the [Configure The Applications In FusionAuth](#configure-the-applications-in-fusionauth) section. Next, build out the `indexRouter` code referenced from the `app.js` file above. @@ -353,233 +197,97 @@ Next, build out the `indexRouter` code referenced from the `app.js` file above. Here's the entire `index.js` file, which should be placed at `routes/index.js`: -```javascript title="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. -```javascript title="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 `logoutUrl` 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](/docs/apis/authentication#managing-api-keys). +The `clientId` and `clientSecret` are the values noted in the administrative user interface when you created the application in FusionAuth. The `fusionAuthURL` value needs to match your FusionAuth location, typically `http://localhost:9011`. If the FusionAuth server is running at a different hostname, update that. -```javascript title="Home page route" -//... +The first argument to the FusionAuth client creation 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](/docs/apis/authentication#managing-api-keys). -/* 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. -```javascript title="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. -```javascript title="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. +Recall that there are three sessions present in this system: the FusionAuth session and one for each 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. -```javascript title="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. -```javascript title="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: -```pug title="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. +The content is displayed using the `block content` directive. Above it is a menu which lets users switch between both applications. -```pug title="Login view" -extends layout +Next, the login view: -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. -```pug title="Index view" -extends layout +Then, create the index view: -block content - h1= title + - p Hello #{user.firstName} - a(href=logoutUrl) Log out - - p Welcome to #{title} -``` - -This welcomes the user by name. +This welcomes the user by name. If you were building a more complicated application, this is where you would put functionality that required a user to be authenticated.. There is some CSS in this application too; the CSS is available in the GitHub repository, but won't be covered here. @@ -601,19 +309,10 @@ In real life, these applications would have different functionality. For this gu * 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. -```pug title="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. @@ -621,19 +320,24 @@ html PORT=3001 npm start ``` -And that's it. You've just created a second application. +And that's it. You've just created a second application. Congrats! ## 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 how you can test the work you've just done: + +* Visit `http://piedpiper.local:3000`. You'll be redirected to the FusionAuth login screen. +* Check Keep Me Signed In +* 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. 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. +If you are testing these applications with a modern browser, logout won't work due to browser quirks when you are running over `http`. However, if you set up TLS and change the redirects to happen over `https`, then logout works. ## Other Scenarios @@ -657,7 +361,7 @@ The single sign-on session duration can be configured at the Tenant level. Navig 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: +The length of a single sign-on session can be different from the session length for individual applications. When a request to an application occurs, there are four possible scenarios: *Single sign-on session scenarios* diff --git a/astro/src/content/docs/release-notes/index.mdx b/astro/src/content/docs/release-notes/index.mdx index 8d8456fa98..0f94a40d8b 100644 --- a/astro/src/content/docs/release-notes/index.mdx +++ b/astro/src/content/docs/release-notes/index.mdx @@ -17,6 +17,13 @@ import ReleaseNoteHeading from 'src/components/docs/release-notes/ReleaseNoteHea Looking for release notes older than 1.23.0? Look in the [release notes archive](/docs/release-notes/archive). Looking to be [notified of new releases?](/docs/operate/roadmap/releases#release-notifications) + + +### Security + +* A XSS (Cross-Site Scripting) vulnerability was identified in the FusionAuth admin UI. + * Resolves [GitHub Issue #2801](https://github.com/FusionAuth/fusionauth-issues/issues/2801) + ### Fixed @@ -101,6 +108,7 @@ Update dependencies. * Applications now have a new Scope Handling Policy. The `Strict` option provides behaviors that are more compliant with the OIDC specification, while the `Compatibility` option provides backwards-compatible behavior. Specifically, `Strict` mode limits information in access tokens and populates Id tokens and UserInfo responses based on the requested OAuth scopes. This option also restricts the UserInfo endpoint to accepting only access tokens containing the `openid` scope. See [Scope handling policy](/docs/lifecycle/authenticate-users/oauth/scopes#scope-handling-policy) for more detail. + * New applications will default to the `Strict` option. If your integration requires the `Compatibility` policy because you need backwards compatible behavior, please specify that option when creating the application. * Resolves [GitHub Issue #1582](https://github.com/FusionAuth/fusionauth-issues/issues/1582) and [GitHub Issue #1475](https://github.com/FusionAuth/fusionauth-issues/issues/1475), thanks to [@awoodobvio](https://github.com/awoodobvio) for the suggestions! * The [Refresh Token Grant](/docs/lifecycle/authenticate-users/oauth/endpoints#refresh-token-grant-request) request now supports requesting a subset of the original scopes. The former behavior was to respond with an `invalid_scope` OAuth error. * Resolves [GitHub Issue #2590](https://github.com/FusionAuth/fusionauth-issues/issues/2590)