Skip to Content
Step-by-Step GuidesSecure a React App

Secure a React App

There are two common ways to connect a browser app to AuthGate.

PathBest forBrowser stores access token?
BFF GatewayMost beginner and ecommerce-style browser apps.No
Direct OAuth2 PKCELearning OAuth2 libraries or building a token-based SPA.The OAuth2 library manages tokens

If you are not sure which one to choose, use the BFF Gateway path first. It is easier to reason about because your frontend calls same-origin URLs like /bff/me and /api/products.

Option 1: Use a BFF Gateway

This is the recommended path for a normal React or Next.js website.

Your frontend does not need an OAuth2 library. AuthGate owns the login redirect, callback, token exchange, and session cookie.

1. Create the OAuth2 client

In IAM > Clients, create or choose an OAuth2 client for the browser app.

The client must allow the BFF callback URL:

https://your-gateway.authgate.site/bff/callback

2. Create a BFF gateway

In API Gateway > Create Gateway:

FieldValue
Gateway typeBFF
Auth typeOAUTH2
OAuth2 clientYour IAM client ID

3. Register the frontend app

Open the gateway, then go to Frontend Apps.

Add the deployed frontend origin:

https://your-react-app.example.com

Users should open the gateway URL, not the raw frontend origin:

https://your-gateway.authgate.site

4. Use BFF endpoints from React

Login button:

export function SignInButton() { return ( <button onClick={() => { window.location.href = '/bff/login?return_to=/' }}> Sign in </button> ) }

Session check:

type BffSession = { authenticated: boolean tenantId?: string gatewayName?: string oauthClientId?: string scope?: string } export async function getSession(): Promise<BffSession> { const response = await fetch('/bff/me', { credentials: 'include' }) if (!response.ok) { return { authenticated: false } } return response.json() }

Logout:

await fetch('/bff/logout', { method: 'POST', credentials: 'include' })

5. Call API routes

Public route:

const products = await fetch('/api/products', { credentials: 'include' }).then((response) => response.json())

Secure route:

const profile = await fetch('/api/profile', { credentials: 'include' }).then((response) => response.json())

If /api/profile is SECURE and the user is not signed in, AuthGate should return an unauthorized response.

Do not save AuthGate access tokens in localStorage when using the BFF pattern. The browser should use the BFF session cookie only.

Option 2: Use direct OAuth2 PKCE

Use this path if you are intentionally learning OAuth2/OIDC libraries.

Install a client library:

npm install react-oidc-context oidc-client-ts

Configure the provider:

import { AuthProvider } from 'react-oidc-context' const oidcConfig = { authority: 'https://iam.authgate.site', client_id: '<your_client_id>', redirect_uri: `${window.location.origin}/auth/callback`, response_type: 'code', scope: 'openid profile email' } export function App() { return ( <AuthProvider {...oidcConfig}> <YourRoutes /> </AuthProvider> ) }

Trigger login:

import { useAuth } from 'react-oidc-context' export function LoginButton() { const auth = useAuth() if (auth.isAuthenticated) { return <p>Signed in as {auth.user?.profile.sub}</p> } return ( <button onClick={() => void auth.signinRedirect()}> Sign in </button> ) }

Call an OAuth2 gateway route:

const token = auth.user?.access_token const response = await fetch('https://your-api.authgate.site/api/orders', { headers: { Authorization: `Bearer ${token}` } })

Which option should I use?

Choose BFF if you want a normal website where login is handled by AuthGate and browser code does not touch access tokens.

Last updated on