Back to Blog
authenticationreactfastapiopenid-connectokta

A Complete Guide to Integrating Okta OpenID Connect SSO with FastAPI and React

A Complete Guide to Integrating Okta SSO with FastAPI and React Okta is a leading identity management solution that simplifies Single Sign-On (SSO) integration. In this guide, we’ll walk through how t

A Complete Guide to Integrating Okta SSO with FastAPI and React

Okta is a leading identity management solution that simplifies Single Sign-On (SSO) integration. In this guide, we’ll walk through how to integrate Okta SSO into a FastAPI backend and a React frontend. By the end of this article, you’ll have a secure and seamless authentication flow in your web application.

Photo by Ed Hardie on Unsplash

1. Setting Up Your Okta Application

To begin, set up an application in Okta:

  1. Log in to the Okta Developer Console.
  2. Navigate to ApplicationsCreate App Integration.
  3. Choose OIDC — OpenID Connect and select Web Application.
  4. Configure the following:

5. Save the app and note down the Client ID, Client Secret, and Issuer URL (we’ll use these later).

2. FastAPI Backend Configuration

Environment Variables

Create a .env file to store sensitive credentials:

OKTA_CLIENT_ID=your-client-id
OKTA_CLIENT_SECRET=your-client-secret
OKTA_ISSUER_URL=https://your-okta-domain.okta.com/oauth2/default
BACKEND_URL=http://localhost:7156
FRONTEND_URL=http://localhost:5173

Dependencies

Install the required libraries:

pip install fastapi uvicorn python-dotenv httpx python-jose

Backend Code

Here’s the core of your main.py file:

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse, HTMLResponse
import os
from dotenv import load_dotenv
from jose import jwt
import httpx

load_dotenv()

app = FastAPI()

CLIENT_ID = os.getenv("OKTA_CLIENT_ID")
CLIENT_SECRET = os.getenv("OKTA_CLIENT_SECRET")
ISSUER_URL = os.getenv("OKTA_ISSUER_URL")
BACKEND_URL = os.getenv("BACKEND_URL")
FRONTEND_URL = os.getenv("FRONTEND_URL")

# Fetch OpenID Connect metadata
metadata = httpx.get(f"{ISSUER_URL}/.well-known/openid-configuration").json()
authorization_url = metadata["authorization_endpoint"]
token_url = metadata["token_endpoint"]

@app.get("/login")
async def login():
redirect_uri = f"{authorization_url}?client_id={CLIENT_ID}&response_type=code&scope=openid&redirect_uri={BACKEND_URL}/signin-oidc"
return RedirectResponse(url=redirect_uri)

@app.get("/signin-oidc")
async def callback(code: str, response: Response):
async with httpx.AsyncClient() as client:
token_response = await client.post(
token_url,
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": f"{BACKEND_URL}/signin-oidc",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
token_response.raise_for_status()
token_data = token_response.json()

access_token = token_data.get("access_token")
html_content = f"""
<html>
<script>
window.opener.postMessage({{"token": "{access_token}"}}, "*");
window.close();
</script>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)

@app.get("/secure-data")
async def secure_data():
return {"message": "You are authenticated!"}

3. React Frontend Configuration

Install Dependencies

Install the necessary React libraries:

npm install axios

Environment Variables

Add the backend base URL to your .env file:

VITE_BASE_REST_URL=http://localhost:7156

Axios Instance

Create a reusable Axios instance for API calls in src/axiosInstance.ts:

import axios from 'axios';

const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_BASE_REST_URL,
timeout: 300000,
});

axiosInstance.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});

export default axiosInstance;

Authentication Flow

Modify your App.tsx to handle authentication:

import { useEffect, useState } from 'react';
import axiosInstance from './axiosInstance';

export default function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);

const checkAuthentication = () => {
const token = localStorage.getItem('access_token');
if (token) {
setIsAuthenticated(true);
} else {
initiateLogin();
}
};

const initiateLogin = () => {
const loginUrl = `${import.meta.env.VITE_BASE_REST_URL}/login`;
const loginPopup = window.open(loginUrl, 'Login', 'width=600,height=700');

window.addEventListener('message', (event) => {
if (event.data?.token) {
localStorage.setItem('access_token', event.data.token);
setIsAuthenticated(true);
loginPopup?.close();
}
});
};

useEffect(() => {
checkAuthentication();
}, []);

if (!isAuthenticated) {
return <div>Authenticating...</div>;
}

return <div>Welcome to your application!</div>;
}

4. Testing Your Application

Run the Backend

Run your FastAPI backend using:

uvicorn main:app --reload

Run the Frontend

Run your React app using:

npm run dev

Test the Flow

  1. Open your app in the browser.
  2. Ensure the login flow redirects you to Okta and returns to the app with a valid access token.
  3. Test an API endpoint like /secure-data to verify the token is correctly passed in the Authorization header.

5. Enhancements and Edge Cases

401 Unauthorized Handling: Add a response interceptor to Axios to handle expired tokens:

axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response.status === 401) {
localStorage.removeItem('access_token');
window.location.reload();
}
return Promise.reject(error);
}
);

Secure Storage: Use secure alternatives like cookies or encrypted storage for production.

6. Conclusion

This guide covers integrating Okta SSO with FastAPI and React for a seamless authentication experience. By following these steps, you can ensure a secure and scalable solution for your application.

Feel free to leave feedback or share how you implemented this in your projects! 🚀

Related Posts

Stop Deploying React Apps Manually!

Stop Deploying React Apps Manually! Set Up GitHub-to-EC2 CI/CD in 15 Minutes (No DevOps Degree Needed) 🚀 In this guide, we’ll set up a zero-downtime CI/CD pipeline that automatically deploys your Rea

reactjsdevopsgithub-actions+2 more
Read More

Design & Developed by Ramxcodes
© 2026. All rights reserved.