Redirecting to fp/install and fp/auth on missing token

This commit is contained in:
Ritul Jadhav 2026-03-31 16:25:19 +05:30
parent 0189726503
commit 0ab0cc563e
4 changed files with 152 additions and 1 deletions

View File

@ -18,6 +18,7 @@ COPY server/index.js ./
COPY server/fdk.js ./
COPY server/postgresFdkStorage.js ./
COPY server/config ./config
# Includes protected and public platform routes such as routes/platformPublic.js.
COPY server/routes ./routes
COPY server/services ./services
COPY --from=client-build /client/dist ./public

View File

@ -4,6 +4,8 @@ import { getRuntimeApplicationId, getRuntimeCompanyId } from './runtimeContext';
const FDK_BOOTSTRAP_ATTEMPT_PREFIX = 'sms_fdk_bootstrap_attempt';
const FDK_BOOTSTRAP_TTL_MS = 2 * 60 * 1000;
const FDK_BOOTSTRAP_REDIRECT_CODE = 'FDK_AUTH_BOOTSTRAP_REDIRECT';
const FDK_SESSION_UNAVAILABLE_CODE = 'FDK_SESSION_UNAVAILABLE';
function getBootstrapStorageKey(companyId) {
return `${FDK_BOOTSTRAP_ATTEMPT_PREFIX}:${companyId}`;
@ -63,14 +65,57 @@ function buildFdkInstallUrl(companyId) {
function createBootstrapRedirectError() {
const error = new Error('Redirecting to FDK auth bootstrap');
error.code = 'FDK_AUTH_BOOTSTRAP_REDIRECT';
error.code = FDK_BOOTSTRAP_REDIRECT_CODE;
return error;
}
function createSessionUnavailableError(message = 'FDK session is unavailable') {
const error = new Error(message);
error.code = FDK_SESSION_UNAVAILABLE_CODE;
return error;
}
function shouldAttemptBootstrap(sessionStatus = {}) {
return Boolean(sessionStatus?.configured) && Boolean(sessionStatus?.needsBootstrap);
}
async function getSessionStatus() {
const response = await apiClient.get('/api/platform/session-status');
return response?.data || {};
}
async function ensureFdkPlatformSession(companyId) {
if (!companyId) {
throw createSessionUnavailableError('Missing company id for FDK session bootstrap');
}
const sessionStatus = await getSessionStatus();
if (sessionStatus?.authenticated) {
clearBootstrapAttempt(companyId);
return sessionStatus;
}
if (shouldAttemptBootstrap(sessionStatus) && shouldBootstrapSession(companyId)) {
const installUrl = buildFdkInstallUrl(companyId);
if (installUrl && typeof window !== 'undefined') {
writeBootstrapAttempt(companyId);
window.location.replace(installUrl);
throw createBootstrapRedirectError();
}
}
throw createSessionUnavailableError(
sessionStatus?.reason
? `FDK session unavailable: ${sessionStatus.reason}`
: 'FDK session is unavailable'
);
}
export async function fetchActiveSalesChannels() {
const companyId = getRuntimeCompanyId();
try {
await ensureFdkPlatformSession(companyId);
const response = await apiClient.get('/api/platform/sales-channels');
clearBootstrapAttempt(companyId);
return normalizeChannelsPayload(

View File

@ -7,6 +7,7 @@ const path = require('path');
const businessesRoutes = require('./routes/businesses');
const platformRoutes = require('./routes/platform');
const platformPublicRoutes = require('./routes/platformPublic');
const { fdkExtension, isFdkConfigured } = require('./fdk');
const app = express();
@ -29,9 +30,11 @@ app.get('/api/health', (req, res) => res.json({
}));
if (fdkExtension) {
app.use('/api/platform', platformPublicRoutes);
app.use(fdkExtension.fdkHandler);
app.use('/api/platform', fdkExtension.platformApiRoutes, platformRoutes);
} else {
app.use('/api/platform', platformPublicRoutes);
app.use('/api/platform', platformRoutes);
}

View File

@ -0,0 +1,102 @@
const express = require('express');
const { SESSION_COOKIE_NAME } = require('@gofynd/fdk-extension-javascript/express/constants');
const { fdkExtension, isFdkConfigured } = require('../fdk');
const router = express.Router();
function normalizeText(value) {
return typeof value === 'string' ? value.trim() : '';
}
function getCompanyId(req) {
return normalizeText(
req.get('x-company-id')
|| req.query.company_id
|| req.query.companyId
|| ''
);
}
function getSessionCookieName(companyId) {
return `${SESSION_COOKIE_NAME}_${companyId}`;
}
function clearSessionCookie(res, companyId) {
res.clearCookie(getSessionCookieName(companyId), {
path: '/',
httpOnly: true,
secure: true,
sameSite: 'None',
partitioned: true,
});
}
router.get('/session-status', async (req, res) => {
const companyId = getCompanyId(req);
if (!isFdkConfigured || !fdkExtension) {
return res.json({
configured: false,
authenticated: false,
companyId,
needsBootstrap: false,
reason: 'fdk_not_configured',
});
}
if (!companyId) {
return res.status(400).json({
configured: true,
authenticated: false,
companyId: '',
needsBootstrap: false,
reason: 'missing_company_id',
});
}
const sessionCookieName = getSessionCookieName(companyId);
const sessionId = normalizeText(req.signedCookies?.[sessionCookieName] || '');
if (!sessionId) {
return res.json({
configured: true,
authenticated: false,
companyId,
needsBootstrap: true,
reason: 'missing_session_cookie',
});
}
try {
const session = await fdkExtension.storage.get(sessionId);
const authenticated = Boolean(
session
&& normalizeText(String(session.company_id || '')) === companyId
&& normalizeText(session.access_token || '')
);
if (!authenticated) {
clearSessionCookie(res, companyId);
}
return res.json({
configured: true,
authenticated,
companyId,
needsBootstrap: !authenticated,
reason: authenticated ? 'ok' : 'missing_or_invalid_session',
});
} catch (error) {
return res.status(503).json({
configured: true,
authenticated: false,
companyId,
needsBootstrap: false,
reason: 'session_status_error',
error: error.message || 'Failed to inspect FDK session',
});
}
});
module.exports = router;