Integrate in Existing Node.js Project
Add Hawcx authentication to an existing Node.js application
Integrating Hawcx Backend SDK into Existing Node.js Projects
This guide walks through adding Hawcx OAuth authentication to an existing Node.js backend.
Step 1: Install the SDK
npm install @hawcx/oauth-clientStep 2: Set Up Environment Variables
Create a .env file or configure your environment with:
# Base URL — from Admin Console → Project Settings (environment-specific)
HAWCX_BASE_URL="<Base URL from Admin Console>"
# Config ID — from Admin Console → Project Settings (tenant routing key)
HAWCX_CONFIG_ID="<Config ID from Admin Console>"
# Client ID — from Admin Console → Project Settings (expected `aud` on id_tokens)
HAWCX_CLIENT_ID="<Client ID from Admin Console>"
# Optional (for delegation / MFA management)
HAWCX_SECRET_KEY=hwx_sk_v1_...Where to find these values
Open the Hawcx Admin Console, go to Project Settings, and copy the Base URL, Config ID, and Client ID. All three are environment-specific.
configId vs clientId
These look similar but are distinct values. configId is the tenant
routing key sent as the X-Config-Id header on token exchange.
clientId is the value the tenant has configured as the aud claim
on issued id_tokens. The SDK passes each to the right place; you just
need both set correctly. See the Quickstart for details.
Load environment variables in your application:
import dotenv from 'dotenv';
dotenv.config();Step 3: Construct the SDK Once at Startup
Use the discovery-mode factory so verification enforces iss / aud /
exp / nbf (not just signature). The discovery fetch happens once at
boot — don't run it per request.
// src/hawcx.ts
import { HawcxOAuth } from '@hawcx/oauth-client';
export const oauth = await HawcxOAuth.fromIssuer({
issuer: process.env.HAWCX_BASE_URL!,
configId: process.env.HAWCX_CONFIG_ID!,
clientId: process.env.HAWCX_CLIENT_ID!,
});The await rejects with DiscoveryError if the issuer is unreachable or
the discovery document is malformed — your bootstrap fails fast rather
than starting with broken verification.
Step 4: Create an Exchange Endpoint
import express from 'express';
import { oauth } from './hawcx'; // singleton from Step 3
const router = express.Router();
router.post('/exchange', async (req, res) => {
try {
const { authCode, codeVerifier } = req.body;
if (!authCode || !codeVerifier) {
return res.status(400).json({ error: 'Missing authCode or codeVerifier' });
}
// Verification enforces signature + iss + aud + exp + nbf
const { claims } = await oauth.exchangeCode(authCode, codeVerifier);
// Find or create user in your database
const user = await findOrCreateUser({
id: claims.sub,
email: claims.email,
});
// Create your application's session/JWT
const sessionToken = generateSessionToken(user);
res.json({
success: true,
sessionToken,
user: { id: user.id, email: user.email },
});
} catch (error) {
console.error('Hawcx exchange error:', error);
res.status(401).json({ error: 'Authentication failed' });
}
});
export default router;Step 5: Integrate with Your User Management
Update your user service to handle Hawcx identities:
// services/userService.ts
import db from '../db';
interface HawcxUser {
id: string; // Hawcx user ID (sub claim)
email?: string;
}
export async function findOrCreateUser(hawcxUser: HawcxUser) {
let user = await db.users.findOne({ hawcx_id: hawcxUser.id });
if (!user) {
user = await db.users.create({
hawcx_id: hawcxUser.id,
email: hawcxUser.email
});
}
return user;
}Optional: Backend-Driven MFA Management
If you need to manage MFA from your backend, use the delegation client with your secret key blob:
import { DelegationClient, MfaMethod } from '@hawcx/oauth-client';
const client = DelegationClient.fromSecretKey({
secretKey: process.env.HAWCX_SECRET_KEY!,
baseUrl: process.env.HAWCX_BASE_URL!,
apiKey: process.env.HAWCX_CONFIG_ID
});
const result = await client.mfa.initiate({
userId: '[email protected]',
mfaMethod: MfaMethod.SMS,
phoneNumber: '+15551234567'
});
await client.mfa.verify({
userId: '[email protected]',
sessionId: result.session_id,
otp: '123456'
});