fusionauth logo
search-interface-symbol
Downloads
Quickstarts
API Docs
SDKs
search-interface-symbol
talk to an expert
Log In
talk to an expert
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
      • Angular
      • C# .NET
      • .NET Core API
      • Express.js
      • Express API
      • Flutter
      • Java Spring
      • Laravel API
      • Python Django
      • Python Flask
      • React
      • Ruby on Rails
      • Ruby on Rails API
      • Vue.js
  • 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
    • Amazon Cognito
    • Duende IdentityServer
    • Firebase
    • Keycloak
    • Microsoft Azure AD B2C
    • Supabase
    • Tutorial
  • Admin Guide
    • Overview
    • Account Portal
    • CLI
    • 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
    • User Support Guide
    • Vulnerabilities
    • 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
      • Integrations
        • CockroachDB
        • Salesforce
    • Passwordless
      • Overview
      • Magic Links
      • WebAuthn & Passkeys
    • SAML v2 IdP
      • Overview
      • Aiven
      • Google
      • PagerDuty
      • SendGrid
      • Tableau Cloud
      • Zendesk
  • Developer Guide
    • Overview
    • API Gateways
      • Overview
      • Amazon API Gateway
      • HAProxy
      • Kong Gateway
      • ngrok Cloud Edge
    • Client Libraries & SDKs
      • Overview
      • Angular
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • Node
      • OpenAPI
      • PHP
      • Python
      • React
      • Ruby
      • Typescript
      • Vue
    • 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 Reg. Update
        • User Reg. Update Complete
        • User Reg. Verified
        • User 2FA Method Add
        • User 2FA Method Remove
        • User Update
        • User Update Complete
    • Guides
      • Overview
      • Anonymous Users
      • 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)
      • User Actions
    • 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
      • Client-side Password Validation
      • Examples
      • Helpers
      • Kickstart Custom Theme
      • Localization
      • Template Variables
      • Tailwind CSS
  • 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
      • Bootstrapping Login
      • 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
    • Hosted Backend
    • 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

    Integrate Your .NET Core API With FusionAuth

    Integrate Your .NET Core API With FusionAuth

    In this article, you are going to learn how to integrate a .NET Core API with FusionAuth. This presupposes you've built an application that is going to retrieve an access token from FusionAuth via one of the OAuth grants. The grant will typically be the Authorization Code grant for users or the Client Credentials grant for programmatic access.

    The token provided by FusionAuth can be stored by the client in a number of locations. For server side applications, it can be stored in a database or on the file system. In mobile applications, store them securely as files accessible only to your app. For a browser application like a SPA, use a cookie if possible and server-side sessions if not.

    Here’s a typical API request flow before integrating FusionAuth with your .NET Core API.

    API access before FusionAuth.
    API access before FusionAuth.

    Here’s the same API request flow when FusionAuth is introduced.

    API access with FusionAuth.
    API access with FusionAuth.

    This document will walk through the use case where a .NET Core API validates the token. You can also use an API gateway to verify claims and signatures. For more information on doing that with FusionAuth, visit the API gateway documentation.

    FusionAuth has a Hosted Backend APIs feature that makes it easier to integrate your API with FusionAuth. These APIs provide a prebuilt solution for getting your app up and running using the OAuth2 Authorization Code grant with PKCE. We have in the past shown you how to create these endpoints yourself, but this solution allows you to get going with your app without writing any backend code dealing with OAuth2. The Hosted Backend APIs deal with the OAuth2 flow and store the client tokens in cookies for you. Your service API can then check the cookies to verify the user is authenticated and authorized. For this to work, your FusionAuth instance, frontend, and API must all be hosted on the same domain.

    Prerequisites

    For this tutorial, you’ll need to have .NET Core, ASP.NET, npx installed.

    You'll also need Docker, since that is how you’ll install FusionAuth.

    The commands below are for macOS, but are limited to mkdir and cd, which have equivalents in Windows and Linux.

    Although this guide shows how to build the .NET Core application using command-line tools, you can also use Visual Studio to build and debug the project.

    Download and Install FusionAuth

    First, make a project directory:

    mkdir integrate-fusionauth && cd integrate-fusionauth

    Then, install FusionAuth:

    curl -o docker-compose.yml https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/docker-compose.yml curl -o .env https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/.env docker compose up -d

    Create a User and an API Key

    Next, log into your FusionAuth instance. You’ll need to set up a user and a password, as well as accept the terms and conditions.

    Then, you’re at the FusionAuth admin UI. This lets you configure FusionAuth manually. But for this tutorial, you're going to create an API key and then you’ll configure FusionAuth using our client library.

    Navigate to Settings -> API Keys. Click the + button to add a new API Key. Copy the value of the Key field and then save the key. It might be a value like CY1EUq2oAQrCgE7azl3A2xwG-OEwGPqLryDRBCoz-13IqyFYMn1_Udjt.

    Doing so creates an API key that can be used for any FusionAuth API call. Save that key value off as you’ll be using it later.

    Configure FusionAuth

    Next, you need to set up FusionAuth. This can be done in different ways, but we’re going to use the .NET Core client library. You can use the client library with an IDE of your preference as well.

    First, make a directory:

    mkdir setup-fusionauth && cd setup-fusionauth

    Then, create a .NET Core project:

    dotnet new console --output SetupFusionauth && cd SetupFusionauth

    Next, you’ll need to import a few NuGet packages:

    dotnet add package JSON.Net dotnet add package FusionAuth.Client

    Copy and paste the following code into Program.cs.

    using System; using io.fusionauth; using io.fusionauth.domain; using io.fusionauth.domain.api; using io.fusionauth.domain.api.user; using System.Collections.Generic; using Newtonsoft.Json; using io.fusionauth.domain.oauth2; using io.fusionauth.domain.search; namespace Setup { class Program { private static readonly String applicationName = ".NET FusionAuth Application"; private static readonly String apiKey = Environment.GetEnvironmentVariable("fusionauth_api_key"); private static readonly String fusionauthURL = "http://localhost:9011"; private static readonly String authorizedRedirectURL = "https://localhost:5001/callback"; private static readonly String logoutURL = "https://localhost:5001/"; private static readonly String applicationId = "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e"; private static readonly String clientSecret = "change-this-in-production-to-be-a-real-secret"; static void Main(string[] args) { if (String.IsNullOrEmpty(apiKey)) { throw new ArgumentException("apiKey", "The API key must be set in the environment variable `fusionauth_api_key`"); } FusionAuthSyncClient client = new FusionAuthSyncClient(apiKey, fusionauthURL); //set the issuer up correctly ClientResponse<TenantResponse> retrieveTenantsResponse = client.RetrieveTenants(); if (!retrieveTenantsResponse.WasSuccessful()) { throw new Exception("couldn't find tenant"); } //should be only one Tenant tenant = retrieveTenantsResponse.successResponse.tenants[0]; Dictionary<String, Object> issuerUpdateMap = new Dictionary<String, Object>(); Dictionary<String, Object> tenantMap = new Dictionary<String, Object>(); tenantMap["issuer"] = fusionauthURL; issuerUpdateMap["tenant"] = tenantMap; ClientResponse<TenantResponse> patchTenantResponse = client.PatchTenant(tenant.id, issuerUpdateMap); if (!patchTenantResponse.WasSuccessful()) { throw new Exception("couldn't update tenant"); } // generate RSA keypair System.Guid rsaKeyId = System.Guid.Parse("356a6624-b33c-471a-b707-48bbfcfbc593"); Key rsaKey = new Key(); rsaKey.algorithm = KeyAlgorithm.RS256; rsaKey.name = ".NET FusionAuth Application"; rsaKey.length = 2048; KeyRequest keyRequest = new KeyRequest(); keyRequest.key = rsaKey; ClientResponse<KeyResponse> keyResponse = client.GenerateKey(rsaKeyId, keyRequest); if (!keyResponse.WasSuccessful()) { throw new Exception("couldn't create RSA key"); } // create application Application application = new Application(); application.oauthConfiguration = new OAuth2Configuration(); application.oauthConfiguration.authorizedRedirectURLs = new List<string>(); application.oauthConfiguration.authorizedRedirectURLs.Add(authorizedRedirectURL); application.oauthConfiguration.requireRegistration = true; application.oauthConfiguration.enabledGrants = new List<GrantType> { GrantType.authorization_code, GrantType.refresh_token }; application.oauthConfiguration.logoutURL = logoutURL; application.oauthConfiguration.proofKeyForCodeExchangePolicy = ProofKeyForCodeExchangePolicy.Required; application.name = applicationName; // assign key from above to sign our tokens. This needs to be asymmetric application.jwtConfiguration = new JWTConfiguration(); application.jwtConfiguration.enabled = true; application.jwtConfiguration.accessTokenKeyId = rsaKeyId; application.jwtConfiguration.idTokenKeyId = rsaKeyId; Guid clientId = Guid.Parse(applicationId); application.oauthConfiguration.clientSecret = clientSecret; ApplicationRequest applicationRequest = new ApplicationRequest(); applicationRequest.application = application; ClientResponse<ApplicationResponse> applicationResponse = client.CreateApplication(clientId, applicationRequest); if (!applicationResponse.WasSuccessful()) { throw new Exception("couldn't create application"); } // register user, there should be only one, so grab the first SearchRequest searchRequest = new SearchRequest(); UserSearchCriteria userSearchCriteria = new UserSearchCriteria(); userSearchCriteria.queryString = "*"; searchRequest.search = userSearchCriteria; ClientResponse<SearchResponse> userSearchResponse = client.SearchUsersByQuery(searchRequest); if (!userSearchResponse.WasSuccessful()) { throw new Exception("couldn't find users"); } User myUser = userSearchResponse.successResponse.users[0]; // patch the user to make sure they have a full name, otherwise OIDC has issues Dictionary<String, Object> fullNameUpdateMap = new Dictionary<String, Object>(); Dictionary<String, Object> userMap = new Dictionary<String, Object>(); userMap["fullName"] = myUser.firstName + " " + myUser.lastName; fullNameUpdateMap["user"] = userMap; ClientResponse<UserResponse> patchUserResponse = client.PatchUser(myUser.id, fullNameUpdateMap); if (!patchUserResponse.WasSuccessful()) { throw new Exception("couldn't update user"); } // now register the user UserRegistration registration = new UserRegistration(); registration.applicationId = clientId; // otherwise we try to create the user as well as add the registration User nullBecauseWeHaveExistingUser = null; RegistrationRequest registrationRequest = new RegistrationRequest(); registrationRequest.user = nullBecauseWeHaveExistingUser; registrationRequest.registration = registration; ClientResponse<RegistrationResponse> registrationResponse = client.Register(myUser.id, registrationRequest); if (!registrationResponse.WasSuccessful()) { throw new Exception("couldn't register user"); } } } }

    Update the application.oauthConfiguration.authorizedRedirectURLs value to http://localhost:3000/profile.html. Update the application.oauthConfiguration.logoutURL value to http://localhost:3000.

    Now you can publish and run the application. Replace <YOUR_API_KEY> with the API key that you generated.

    The setup script is designed to run on a newly installed FusionAuth instance with only one user and no tenants other than Default. To follow this guide on a FusionAuth instance that does not meet these criteria, you may need to modify the above script.

    Refer to the .NET Core client library documentation for more information.

    The path to the SetupFusionauth executable will be different depending on your platform.

    dotnet publish -r osx-x64 fusionauth_api_key=<YOUR_API_KEY> bin/Debug/net7.0/osx-x64/publish/SetupFusionauth

    If you are using PowerShell, you will need to set the environment variable in a separate command before executing the script.

    $env:fusionauth_api_key='<your API key>' bin\Debug\net7.0\win-x64\publish\SetupFusionauth.exe

    If you want to, you can log in to your instance and examine the new API configuration the script created for you. Navigate to the Applications tab to do so.

    Create Your .NET Core API

    Now you are going to create a .NET Core API. While this section builds a simple .NET Core API, you can use the same configuration to build a more complex .NET Core API.

    First, create the skeleton of the .NET Core API. The .NET framework has a generator to build this out.

    dotnet new webapi -o MyAPI && cd MyAPI

    Then, you’ll need to import a few NuGet packages:

    dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt

    You can now start writing the code for your .NET Core API. First, let's create a controller that gives back a JSON message. Create a file called MessageController.cs in the Controllers folder, and add the following code to it.

    using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace MyAPI.Controllers; [ApiController] [Route("message")] [Authorize] public class MessageController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok(new { message= "Hello"}); } }

    This controller returns a JSON object with a simple "Hello" message.

    Next, update the Program.cs file to look like this:

    var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddAuthentication() .AddJwtBearer(options => { options.Events = new() { OnMessageReceived = context => { // Get the token from a cookie context.Token = context.Request.Cookies["app.idt"]; return Task.CompletedTask; } }; options.Authority = "http://localhost:9011"; options.TokenValidationParameters.ValidateAudience = false; options.RequireHttpsMetadata = false; // For testing only, set true in production. }); builder.Services.AddAuthorization(options => options.AddPolicy("ApiScope", policy => { policy.RequireAuthenticatedUser(); //policy.RequireClaim("scope", "api1"); }) ); builder.Services.AddCors(options => { options.AddPolicy(name: "AllowLocalFrontendCORS", policy => { policy .WithOrigins("http://localhost:3000") .AllowCredentials(); }); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseCors("AllowLocalFrontendCORS"); //app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();

    Note the changes in the builder.Services.AddAuthentication() section. This updates the authentication code to extract the JWT from the app.idt cookie. The app.idt cookie has an OpenID Connect JWT that contains the user's identity and claims. The app.idt cookie is set by the Hosted Backend APIs when the user logs in. The app.idt cookie is set to the same domain as the FusionAuth instance. This allows the .NET Core API to read the cookie and extract the JWT. Also note that the issuer is set to http://localhost:9011 which is the default FusionAuth URL. If you are using a different URL, you should update this value. The .NET authentication libraries will seamlessly validate the JWT, including the audience, and extract the identity and claims. There is no more you need to do on your part!

    You can now start up your server. You should do it in a new terminal window so that you can continue to edit the .NET Core code.

    To see the results, publish this application and run it. There are multiple ways of deploying an application, but publishing ensures your deployment process is repeatable. You can use the RID catalog to build different versions of this application for different platforms. Here’s the command to publish a standalone executable you could deploy behind a proxy like Nginx:

    dotnet publish -r osx-x64

    Then run the executable:

    ASPNETCORE_ENVIRONMENT=Development bin/Debug/net7.0/osx-x64/publish/MyAPI

    You can use curl to see the output of the API:

    curl -v http://localhost:5000/message

    This command should return a 401 Unauthorized response, indicating that the route is secure. The next step is to set up the FusionAuth Hosted Backend API and log in to get a JWT in a cookie that your API can read.

    Create a Login Redirect Page

    To demonstrate how simple it is to use the Hosted Backend API, you are going to create a simple login page that redirects to the Hosted Backend API. The login page will be a plain HTML page with no special code or libraries. This page will manage the redirect to the FusionAuth Hosted Backend API login, which will handle the OAuth flow, and then have a button to call your API with the JWT cookie.

    Create a new directory for the login page:

    mkdir LoginPage && cd LoginPage

    Then, create two new files: index.html and profile.html. Add the following code to the index.html file:

    <html> <head> <title>FusionAuth Hosted Backend API Demo</title> </head> <body> <h1>FusionAuth Hosted Backend API Demo</h1> <p> <a href="http://localhost:9011/app/login/e9fdb985-9173-4e01-9d73-ac2d60d1dc8e?redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fprofile.html&state=1234&scope=openid%20offline_access">Login</a> </p> </body> </html>

    This page is the main page, which has a link that redirects to the FusionAuth Hosted Backend API login route. Note the format of the URL in the anchor href: GET /app/login/{clientId}?redirect_uri={redirectUri}&state={state}&scope={scope}.

    In this case, clientId is e9fdb985-9173-4e01-9d73-ac2d60d1dc8e, as this is hardcoded in the setup script.

    The redirect_uri is the URL the Hosted Backend API will redirect to when the login flow is complete, in this case, the profile.html page.

    The state parameter is any information that you would like returned on successful login.

    The scope is the OAuth scopes you want to request. In this example, the openid scope is requested, which is required to get the app.idt cookie containing the JWT with the user's claims. You can request other scopes too, such as offline_access to get a refresh token, which can be used to get a new access token when the current one expires. The refresh token is stored in a cookie called app.rt.

    Now add the following to the profile.html file:

    <html> <head> <title>FusionAuth Hosted Backend API Demo</title> </head> <body> <h2>Here is your FusionAuth Profile, from calling the /me endpoint on FusionAuth</h1> <p><em> if it is not showing, it means you are not logged in</em></p> <pre id="profile"></pre> <button id="call-api-button">Call the API</button> <h2>Here are the results of calling the API</h2> <pre id="api-results"> </pre> </body> <script> (async () => { const response = await fetch( "http://localhost:9011/app/me/", { method: 'GET', credentials: "include" } ); const fusionProfile = await response.json(); document.getElementById("profile").innerHTML = JSON.stringify(fusionProfile, null, 2); } )(); // Call the API on button press document.getElementById("call-api-button").onclick = async function () { let response = await fetch( "http://localhost:5000/message", { method: 'GET', credentials: "include" } ); if (response.status == 401) { // Refresh the token console.log("401 error, refreshing token..."); const refreshResponse = await fetch( "http://localhost:9011/app/refresh/e9fdb985-9173-4e01-9d73-ac2d60d1dc8e", { method: 'POST', credentials: "include", body: "" } ); // retry the call to the api after refresh: console.log("Retrying the call to the API..") response = await fetch( "http://localhost:5000/message", { method: 'GET', credentials: "include" } ); } const message = await response.json(); document.getElementById("api-results").innerHTML = JSON.stringify(message, null, 4); } </script> </html>

    This page is the page that the Hosted Backend API will redirect to after the login flow is complete.

    The page first calls the /me route, which is part of the FusionAuth Hosted Backend API and returns the identity of the currently logged-in user.

    The profile.html page also has a button that calls the message route of the .NET Core API. Note that the fetch call for this button includes the credentials: 'include' option. This option tells the browser to include the cookies in the request so that the .NET Core API can read the app.idt cookie and extract the JWT.

    If the API call is successful, the message route will return a "Hello" message. If the API call is not successful, the message route will return a 401 Unauthorized response. In this case, the code will try refreshing the access token using the refresh token in the app.rt cookie. To do this, the code makes a fetch request to the refresh token route of the Hosted Backend API. If the refresh token is valid, FusionAuth's Hosted Backend API will return a new access token. The code then tries the message route again with the new access token.

    A note on CORS (Cross-Origin Resource Sharing): For this setup to work, all components, including the web page, the .NET Core API, and FusionAuth, must be on the same domain. This is because the app.idt JWT cookie and app.rt refresh cookie are set to the same domain as the FusionAuth instance. Since everything runs on the same domain, CORS won't usually be an issue. However, you'll be running all of this on localhost to test, with each component running on a different port, which will cause CORS issues. For this reason, we need to enable CORS on FusionAuth for the login webpage to access the FusionAuth Hosted Backend API. To do this, navigate to Settings -> System on the sidebar, and then select the CORS tab. Enable CORS, and check GET, POST, and OPTIONS. Enable Allow Credentials, and add http://localhost:3000 to the list of Allowed origins.

    CORS settings in FusionAuth for testing on Localhost

    You can now serve up the login and profile static pages. An easy way to do this is to use the http-server package via npx. You can use any other web server to serve the files, but accessing them directly from the filesystem won't work. Change to the LoginPage directory and run the following command:

    npx http-server -a localhost -p 3000

    This will serve the website on http://localhost:3000

    Testing the API Flow

    Navigate to the login webpage at http://localhost:3000. Click the Login button. This will redirect you to the FusionAuth Hosted Backend API login page. Enter the email and password of the user created in the setup script earlier for your FusionAuth instance. You will be redirected to the login webpage, and the results from the /me FusionAuth endpoint alongside the Call the API button will be shown. Click this button to call the message route of the .NET Core API, which will echo back a "Hello" message. You should see something similar to the following output:

    Output of the /me call and the dotnet API call

    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
    Blog
    Expert Advice
    Download
    Release Notes
    Subscribe for developer updates