How to Integrate Fabrixly-IDS with React and Node.js

This guide walks you through integrating Fabrixly-IDS authentication in a React single-page application (SPA) backed by a Node.js / Express API server.


πŸ—οΈ Architecture Overview

  1. Frontend (React): Handles login redirection, parses the OIDC callback, stores the tokens, and attaches the JWT access_token to API calls.
  2. Identity Server (Fabrixly-IDS): Authenticates users and issues standard OIDC JWT tokens.
  3. Backend (Node.js): Validates incoming JWT tokens in the Authorization header and serves protected API responses.

Part A: Frontend Setup (React)

For React, we use the standard, secure react-oidc-context library which supports Authorization Code Flow with PKCE.

1. Install Dependencies

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

2. Configure the AuthProvider

Wrap your application in the AuthProvider from react-oidc-context.

Create src/main.jsx:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import { AuthProvider } from "react-oidc-context";

const oidcConfig = {
  authority: "https://ids.fabrixly.com/oidc",
  client_id: "your-react-client-id", // Registered in Admin Console
  redirect_uri: "http://localhost:5173/callback",
  response_type: "code",
  scope: "openid profile email offline_access",
  onSigninCallback: () => {
    // Clear URL parameters after successful login redirect
    window.history.replaceState({}, document.title, window.location.pathname);
  }
};

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <AuthProvider {...oidcConfig}>
      <App />
    </AuthProvider>
  </React.StrictMode>
);

3. Implement Login & User Profile

Create src/App.jsx:

import React, { useEffect, useState } from "react";
import { useAuth } from "react-oidc-context";

function App() {
  const auth = useAuth();
  const [apiMessage, setApiMessage] = useState("");

  if (auth.isLoading) return <div>Loading auth...</div>;
  if (auth.error) return <div>Authentication Error: {auth.error.message}</div>;

  const callProtectedApi = async () => {
    try {
      const response = await fetch("http://localhost:3000/api/protected", {
        headers: {
          Authorization: `Bearer ${auth.user?.access_token}`
        }
      });
      const data = await response.json();
      setApiMessage(data.message || data.error);
    } catch (err) {
      setApiMessage("Failed to connect to Node.js backend");
    }
  };

  if (auth.isAuthenticated) {
    return (
      <div style={{ padding: "40px" }}>
        <h1>Welcome, {auth.user?.profile.name}! πŸ‘‹</h1>
        <p>Email: {auth.user?.profile.email}</p>
        <button onClick={() => auth.removeUser()}>Log Out</button>
        <hr />
        <button onClick={callProtectedApi}>Call Node.js Protected API</button>
        {apiMessage && <p><strong>API Response:</strong> {apiMessage}</p>}
      </div>
    );
  }

  return (
    <div style={{ padding: "40px", textAlign: "center" }}>
      <h1>React + Fabrixly-IDS πŸ”</h1>
      <button onClick={() => auth.signinRedirect()}>Sign In with Fabrixly</button>
    </div>
  );
}

export default App;

Part B: Backend Setup (Node.js + Express)

The backend acts as a Resource Server that validates OIDC JWT access tokens issued by Fabrixly-IDS using standard JSON Web Key Sets (JWKS).

1. Install Dependencies

npm install express cors jsonwebtoken jwks-rsa

2. Implement JWT Validation Middleware

Create server.js:

const express = require("express");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const jwksClient = require("jwks-rsa");

const app = express();
app.use(cors());
app.use(express.json());

const IDS_ISSUER = "https://ids.fabrixly.com/oidc";

// Configure JWKS client to retrieve cryptographic signing keys dynamically
const client = jwksClient({
  jwksUri: `${IDS_ISSUER}/jwks`,
  cache: true,
  rateLimit: true,
  jwksRequestsPerMinute: 10
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) return callback(err);
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

// Authentication Middleware
const requireAuth = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Missing or invalid authorization token" });
  }

  const token = authHeader.split(" ")[1];

  jwt.verify(token, getKey, {
    issuer: IDS_ISSUER,
    algorithms: ["RS256"]
  }, (err, decoded) => {
    if (err) {
      return res.status(403).json({ error: "Token validation failed: " + err.message });
    }
    req.user = decoded; // Contains sub (userId), email, scope, etc.
    next();
  });
};

// Protected API Endpoint
app.get("/api/protected", requireAuth, (req, res) => {
  res.json({
    message: `Hello from Node.js! Your user ID is ${req.user.sub}.`
  });
});

app.listen(3000, () => console.log("Backend running on http://localhost:3000"));

Part C: Registering the Client in Admin Console

  1. Navigate to the Clients section of your Fabrixly-IDS Admin Console.
  2. Click Create Client and fill in the properties:
    • Client Name: React Client App
    • Grant Types: authorization_code, refresh_token
    • Response Types: code
    • Redirect URIs: http://localhost:5173/callback
    • Token Endpoint Auth Method: none (required for SPAs / public clients)
  3. Save the configurations. You're ready to test!

Subscribe to The Fabrixly Blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe