Most apps that you build with Firebase’s backend services, such as Realtime Database, Cloud Firestore, and Cloud Storage, need some way to sign users in: among other things, this lets you provide a consistent experience across sessions and devices, and lets you set user-specific permissions. Firebase Authentication helps you meet this requirement by providing libraries and services that you can use to quickly build a new sign-in system for your app.
But what if your organization already uses a service such as Okta to handle user identity? With Firebase Custom Authentication, you can use any user identity service (including Okta) to authenticate with Firebase, and this post will show you how.
You’ll learn how to build a Firebase and Okta integration, which will have two components:
By the way, this approach can also be used with some modification for other identity services, such as Auth0, Azure Active Directory, or your own custom system.
Ready to get started? Great! But, before you write any code, you’ll need to set up your Okta and Firebase projects.
First, set up an Okta project on the Okta Developer site:
Set the Base URIs and Login redirect URIs to the location where you plan to host your web frontend (http://localhost:5000 if you’re using the Firebase Hosting emulator) and enable the Authorization Code grant type.
http://localhost:5000
When you’re done, take note of the app's Client ID for later.
Then, set up a Firebase project in the Firebase console:
If you plan to eventually host your web app with Firebase, you can automatically set up Firebase Hosting and simplify configuration by enabling Also set up Firebase Hosting for this app.
Finally, if you plan to deploy your token exchange endpoint as a Cloud Function:
Now that your projects are set up, you’ll write the crucial piece: the token exchange endpoint.
The job of the token exchange endpoint is to take a user’s Okta access token and, if it’s valid, produce a Firebase custom authentication token that represents the same user.
This endpoint needs to be able to verify the authenticity of the Okta access token. To accomplish this, use the Express.js middleware provided in Okta’s developer documentation (reproduced below, with minor modifications):
const OKTA_ORG_URL = // Your Okta org URL const OktaJwtVerifier = require('@okta/jwt-verifier'); const oktaJwtVerifier = new OktaJwtVerifier({ issuer: `${OKTA_ORG_URL}/oauth2/default` }); // Middleware to authenticate requests with an Okta access token. const oktaAuth = async (req, res, next) => { const authHeader = req.headers.authorization || ''; const match = authHeader.match(/Bearer (.+)/); if (!match) { res.status(401); return next('Unauthorized'); } const accessToken = match[1]; try { const jwt = await oktaJwtVerifier.verifyAccessToken( accessToken, 'api://default'); req.jwt = jwt; return next(); // Pass the request on to the main route. } catch (err) { console.log(err.message); res.status(401); return next('Unauthorized'); } }
Any endpoint protected by this middleware will require a valid Okta access token in the Authorization header. If the token is valid, it will insert the decoded token into the request before passing the request along by calling next().
Authorization
next()
Now, you can write the token exchange endpoint:
const express = require('express'); const app = express(); const cors = require('cors')({origin: 'https://YOUR_DOMAIN'}); const firebaseAdmin = require('firebase-admin'); const firebaseApp = firebaseAdmin.initializeApp(); // Get a Firebase custom auth token for the authenticated Okta user. // This endpoint uses the `oktaAuth` middleware defined above to // ensure requests have a valid Okta access token. app.get('/firebaseCustomToken', [cors, oktaAuth], async (req, res) => { const oktaUid = req.jwt.claims.uid; try { const firebaseToken = await firebaseApp.auth().createCustomToken(oktaUid); res.send(firebaseToken); } catch (err) { console.log(err.message); res.status(500).send('Error minting token.'); } });
This endpoint uses the Firebase Admin SDK to mint a Firebase custom authentication token using the user’s Okta UID. When you sign a user in with this token for the first time (on the frontend), Firebase Authentication will add a user record with the same UID to your project.
This process of using an Okta access token to acquire a Firebase custom token is the key idea behind integrating Okta and Firebase. But, let’s go one step further and write a simple web frontend to demonstrate the use of the endpoint.
The demo frontend is a plain HTML and JavaScript web app that uses the Firebase Authentication Web SDK and Okta’s sign-in widget library.
Start with two containers: one for authenticated user content and one for Okta’s sign-in widget:
<div id="authenticated-user-content" hidden> <h2>Authenticated with Firebase</h2> <p id="user-info"></p> <button onclick="firebase.auth().signOut();">Sign out</button> </div> <div id="signin-widget" hidden></div>
Set up a Firebase authentication state listener that shows some user profile information to signed-in users and Okta’s sign-in widget to signed-out users:
const oktaSignIn = new OktaSignIn({ baseUrl: OKTA_ORG_URL, redirectUri: window.location.url, authParams: { display: 'page', }, el: '#signin-widget', }); firebase.auth().onAuthStateChanged((user) => { if (user) { // User is signed in. Display some user profile information. document.getElementById('user-info').innerHTML = `Hi, ${user.displayName}! Your email address is ${user.email} and your UID is ${user.uid}.`; document.getElementById('authenticated-user-content').hidden = false; document.getElementById('signin-widget').hidden = true; } else { // User is signed out. Display the Okta sign-in widget. oktaSignIn.showSignInToGetTokens({ clientId: OKTA_CLIENT_ID, redirectUri: window.location.url, getAccessToken: true, getIdToken: true, scope: 'openid profile email', }); document.getElementById('authenticated-user-content').hidden = true; document.getElementById('signin-widget').hidden = false; } });
When a user signs in with Okta’s widget, their browser briefly redirects to Okta’s authorization server, and then, assuming the user signed in successfully, redirects back to your app with the response.
Use Okta’s sign-in library to get the Okta access token from the response and use the access token to get a Firebase custom token from your token exchange endpoint:
if (oktaSignIn.hasTokensInUrl()) { // Get the access token from Okta. const oktaTokenResponse = await oktaSignIn.authClient.token.parseFromUrl(); const accessToken = oktaTokenResponse.tokens.accessToken.value; // Use the access token to call the firebaseCustomToken endpoint. const firebaseTokenResponse = await fetch(CUSTOM_TOKEN_ENDPOINT, { headers: { 'Authorization': `Bearer ${accessToken}`, } }); const firebaseToken = await firebaseTokenResponse.text(); // (Continued below.) }
And finally, authenticate with Firebase using the custom token:
// (Continued from above.) try { await firebase.auth().signInWithCustomToken(firebaseToken); } catch (err) { console.error('Error signing in with custom token.'); }
When the call to signInWithCustomToken() completes, the auth state listener will detect the change and display the user’s profile information.
signInWithCustomToken()
At this point, the user is authenticated with Firebase and you can use any of Firebase’s authentication-enabled services, such as Realtime Database, Cloud Firestore, and Cloud Storage. See the Security Rules documentation for more information on granting resource access to authenticated users.
For the complete demo app and backend that the code snippets above came from, see the Authenticate with Firebase using Okta sample on GitHub.