This sample demonstrates how to integrate Frontegg's hosted login into a React app, with a complete implementation of the OAuth 2.0 Device Authorization Grant (RFC 8628). Use this as a reference for building verification pages that let users approve or deny device access from a browser.
- Redirect users to Frontegg's hosted login
- Enable a fully integrated self-service portal
- Manage and track user authentication state
- Access and display user profile details
- Handle account state and data with ease
- Implement seamless account switching functionality
- Authorize devices via the OAuth 2.0 Device Authorization Grant flow
The Device Authorization Grant allows input-constrained devices (smart TVs, CLIs, IoT devices) to obtain tokens by having the user sign in and approve access on a secondary device (phone or laptop).
Device App Frontegg APIs This App (Verification Page)
(e.g. CLI, TV) /activate?user_code=XXXX-XXXX
| | |
| 1. POST /device/authorize | |
|------------------------------>| |
| { device_code, user_code } | |
|<------------------------------| |
| | |
| Display user_code + URL | |
| pointing to this app | |
| | 2. User opens /activate |
| |<-------------------------------|
| | 3. Auto-redirect to login |
| | (if not authenticated) |
| |<-------------------------------|
| | 4. GET /device?user_code= |
| |<-------------------------------|
| | { appName, scopes, ... } |
| |------------------------------>|
| | 5. User clicks Approve/Deny |
| | POST /device/verify |
| |<-------------------------------|
| | |
| 6. POST /token (polling) | |
|------------------------------>| |
| { access_token, id_token, | |
| refresh_token } | |
|<------------------------------| |
DeviceModal — src/components/DeviceModal.tsx
A modal dialog rendered on the main account page. The authenticated user enters the XXXX-XXXX code shown on their device. The modal validates the code format and navigates the user to the verification page via React Router:
/activate?user_code=XXXX-XXXX
The modal is triggered by the Verify Device button in AccountInfo.
DeviceVerifyPage — src/components/DeviceVerifyPage.tsx
The verification page mounted at /activate. It handles the complete user-side flow:
| State | What happens |
|---|---|
loading |
Reads user_code from the URL. If the user is not authenticated, calls loginWithRedirect — Frontegg hosted login redirects back after sign-in. |
confirm |
Calls GET /frontegg/oauth/device?user_code=… with the user's bearer token. Displays the app name, user code, and requested scopes. Shows Approve and Deny buttons. |
done |
Calls POST /frontegg/oauth/device/verify with { user_code, approved }. Shows a success or denial confirmation and a Back to Account button. |
error |
Shown when no code is provided or the code is expired/invalid. |
The component uses ContextHolder.getAccessToken() from @frontegg/react to obtain the bearer token — no manual token handling is needed.
/ → Main (AccountInfo + Verify Device button)
/activate → DeviceVerifyPage (approval/denial UI)
* → redirect to /
BrowserRouter wraps FronteggProvider in App.tsx so that React Router navigation works correctly without triggering Frontegg re-initialization. The * catch-all route handles Frontegg's OAuth callback redirects gracefully.
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
GET |
/frontegg/oauth/device?user_code= |
Bearer token | Fetch device info (app name, scopes, status) |
POST |
/frontegg/oauth/device/verify |
Bearer token | Approve or deny the device request |
The device-side endpoints (
POST /device/authorizeandPOST /token) are called by the device app, not this verification page.
- Node.js
- npm (comes with Node.js)
Don't have an account yet? No worries. This project includes sandbox credentials so you can test it right away!
If you don't have a Frontegg account or prefer to use the sandbox credentials, feel free to skip to step below.
If you're using your own credentials, follow the guidelines below.
- Go to Frontegg Portal
- Get your application ID from [ENVIRONMENT] → Applications
- Get your Frontegg domain from the Frontegg Portal → [ENVIRONMENT] → Keys & domains
- This sample runs on
http://localhost:3000. Make sure to add it under → [ENVIRONMENT] → Authentication → Login method → Redirect URLs - Add
http://localhost:3000under → [ENVIRONMENT] → Keys & domains → Allowed origins - Update your application's credentials in
src/config/sanboxContextOptions.ts
git clone <repo>npm installnpm startThe app will be available at http://localhost:3000.
Note:
client_idin OAuth 2.0 / RFC 8628 terminology refers to the registered OAuth application — in Frontegg terms, this is the applicationId found under [ENVIRONMENT] → Applications in the Frontegg Portal.
- Start the app and sign in
- Click Verify Device on the account page
- Request a device code from the Frontegg API (simulating a device):
curl -X POST https://{your-domain}/frontegg/oauth/device/authorize \ -H "Content-Type: application/json" \ -d '{"client_id": "your-client-id"}' - Copy the
user_codefrom the response (e.g.BCKF-DHLM) - Enter it in the modal and click Continue — you will be taken to
/activate?user_code=BCKF-DHLM - Review the app name and scopes, then click Approve or Deny
- Poll for tokens on the device side to confirm the flow completed:
curl -X POST https://{your-domain}/frontegg/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": "<device_code from step 3>", "client_id": "your-client-id" }'

