Filter by title

Authorization in React UI

OAuth is preconfigured in ABP React UI templates. When you create a React solution with ABP Studio v3.0+ or abp new --modern --ui-framework react, the template includes OpenID Connect settings, an OpenIddict client, route guards, and authentication hooks.

The React app authenticates against the ABP Auth Server using the Authorization Code flow with PKCE, which is the recommended flow for browser-based applications.

Packages

The template uses these packages for authentication:

Package Purpose
@volo/abp-oidc-auth Framework-agnostic OIDC client helpers for ABP/OpenIddict backends.
@volo/abp-react-oidc-auth React adapter for the ABP OIDC client.
oidc-client-ts Underlying OIDC protocol implementation.

The package list also includes @volo/abp-app-config and @volo/abp-react-app-config, which are used to fetch application configuration and permissions after authentication.

OAuth Configuration

The OIDC settings are resolved from runtime configuration first and fall back to src/env.ts.

export function getOAuthConfig(): {
  issuer: string
  redirectUri: string
  clientId: string
  scope: string
  responseType: 'code'
} {
  return {
    issuer: loadedConfig?.oAuthConfig?.issuer ?? env.oauth.issuer,
    redirectUri: loadedConfig?.oAuthConfig?.redirectUri ?? env.oauth.redirectUri,
    clientId: loadedConfig?.oAuthConfig?.clientId ?? env.oauth.clientId,
    scope: loadedConfig?.oAuthConfig?.scope ?? env.oauth.scope,
    responseType: 'code',
  }
}

The important configuration values are:

  • oAuthConfig.issuer: Auth Server / OpenIddict authority URL.
  • oAuthConfig.redirectUri: URL where the Auth Server redirects after login.
  • oAuthConfig.clientId: OpenIddict client ID, normally <ProjectName>_App.
  • oAuthConfig.scope: Scopes requested by the React app.

See Environment Variables for the full runtime configuration model.

Initializing Authentication

The app loads runtime configuration before initializing OIDC:

async function bootstrap() {
  await loadRuntimeConfig()
  initUserManager()
  createRoot(document.getElementById('root')!).render(
    <StrictMode>
      <App />
    </StrictMode>
  )
}

initUserManager() creates the ABP React OIDC client:

client = createAbpReactOidcAuth({
  authority: config.issuer,
  clientId: config.clientId,
  redirectUri: config.redirectUri,
  postLogoutRedirectUri: config.redirectUri,
  scope: config.scope,
  responseType: config.responseType,
  automaticSilentRenew: true,
  userStoreType: 'localStorage',
  userStorePrefix: `oidc.${config.clientId}`,
  silentRedirectUri: `${window.location.origin}/silent-renew.html`,
})

The template stores the OIDC user in local storage and enables silent renewal with public/silent-renew.html.

Lower-Level OIDC Client

@volo/abp-oidc-auth is the framework-agnostic client used by the React OIDC adapter. Use it directly in another JavaScript runtime or supply it to createAbpReactOidcAuth:

import { createAbpOidcAuth } from '@volo/abp-oidc-auth'
import { createAbpReactOidcAuth } from '@volo/abp-react-oidc-auth'

const client = createAbpOidcAuth({
  authority: 'https://localhost:44301/',
  clientId: 'MyProject_App',
  redirectUri: window.location.origin,
  postLogoutRedirectUri: window.location.origin,
  scope: 'offline_access MyProject',
})

const auth = createAbpReactOidcAuth({ client })
await client.init()

Use subscribe() for ABP authentication lifecycle events and getSnapshot() for the current user, profile, token and initialization state. clearStaleState() removes abandoned OIDC state entries. The client also exposes the underlying UserManager, its events and the configured authority for integrations that need lower-level OIDC control.

Auth Provider and Hook

AuthProvider wraps the app and handles the OIDC callback:

export function AuthProvider({ children }: { children: ReactNode }) {
  const authClient = getAuthClient()

  useEffect(() => {
    const params = new URLSearchParams(window.location.search)
    if (!params.has('code') || !params.has('state')) return
    void authClient.handleSigninCallback().then(() =>
      window.history.replaceState({}, document.title, window.location.pathname)
    )
  }, [])

  return <authClient.AuthProvider>{children}</authClient.AuthProvider>
}

Use useAuth() in components:

import { useAuth } from '@/lib/auth/AuthContext'

export function LoginButton() {
  const { isAuthenticated, isLoading, login, logout, user } = useAuth()

  if (isLoading) return null

  return isAuthenticated ? (
    <button onClick={() => void logout()}>{user?.name ?? 'Logout'}</button>
  ) : (
    <button onClick={() => void login()}>Login</button>
  )
}

Route Protection

The React template uses TanStack Router. Protected routes use beforeLoad guards.

const identityLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/identity',
  component: IdentityLayout,
  beforeLoad: authGuard,
})

authGuard checks the current OIDC user and redirects unauthenticated users to the Auth Server:

export async function authGuard({ location }: GuardContext) {
  const user = await userManager.getUser()
  if (!user || user.expired) {
    await userManager.signinRedirect({
      state: { returnUrl: location.href },
    })
    throw new Error('Redirecting to login')
  }
}

Routes that also require a permission use createPermissionGuard:

const usersRoute = createRoute({
  getParentRoute: () => identityLayoutRoute,
  path: 'users',
  component: UsersPage,
  beforeLoad: createPermissionGuard('AbpIdentity.Users'),
})

Permission checks are explained in Permission Management.

OpenIddict Clients

The generated OpenIddict clients depend on the template:

  • Layered and single-layer modern templates use the main React client, normally <ProjectName>_App.
  • Microservice modern templates also include an Admin Console client, normally <ProjectName>_AdminConsole, because the Admin Console is a separate React app.

If you change URLs after generation, update both the runtime configuration and the corresponding OpenIddict client redirect URLs.

See Also

Contributors


Last updated: July 17, 2026 Edit this page on GitHub

Was this page helpful?

Please make a selection.

To help us improve, please share your reason for the negative feedback in the field below.

Please enter a note.

Thank you for your valuable feedback!

Please note that although we cannot respond to feedback, our team will use your comments to improve the experience.

ABP Community Talks
Low-Code, High Precision
13 Aug, 17:00
Online
Watch the Event
ABP Live Webinar
Webinar Calendar Webinar Calendar
Discover
ABP Platform
Register Now
Oct 01
Thursday,
17:00 UTC
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.