feat(api): add unified v2 gateway and mobile read slice
This commit is contained in:
129
backend/unified-api/src/routes/auth.js
Normal file
129
backend/unified-api/src/routes/auth.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import express from 'express';
|
||||
import { AppError } from '../lib/errors.js';
|
||||
import { parseClientSignIn, parseClientSignUp, signInClient, signOutActor, signUpClient, getSessionForActor } from '../services/auth-service.js';
|
||||
import { verifyFirebaseToken } from '../services/firebase-auth.js';
|
||||
|
||||
const defaultAuthService = {
|
||||
parseClientSignIn,
|
||||
parseClientSignUp,
|
||||
signInClient,
|
||||
signOutActor,
|
||||
signUpClient,
|
||||
getSessionForActor,
|
||||
};
|
||||
|
||||
function getBearerToken(header) {
|
||||
if (!header) return null;
|
||||
const [scheme, token] = header.split(' ');
|
||||
if (!scheme || scheme.toLowerCase() !== 'bearer' || !token) return null;
|
||||
return token;
|
||||
}
|
||||
|
||||
async function requireAuth(req, _res, next) {
|
||||
try {
|
||||
const token = getBearerToken(req.get('Authorization'));
|
||||
if (!token) {
|
||||
throw new AppError('UNAUTHENTICATED', 'Missing bearer token', 401);
|
||||
}
|
||||
|
||||
if (process.env.AUTH_BYPASS === 'true') {
|
||||
req.actor = { uid: 'test-user', email: 'test@krow.local', role: 'TEST' };
|
||||
return next();
|
||||
}
|
||||
|
||||
const decoded = await verifyFirebaseToken(token, { checkRevoked: true });
|
||||
req.actor = {
|
||||
uid: decoded.uid,
|
||||
email: decoded.email || null,
|
||||
role: decoded.role || null,
|
||||
};
|
||||
return next();
|
||||
} catch (error) {
|
||||
if (error instanceof AppError) return next(error);
|
||||
return next(new AppError('UNAUTHENTICATED', 'Token verification failed', 401));
|
||||
}
|
||||
}
|
||||
|
||||
export function createAuthRouter(options = {}) {
|
||||
const router = express.Router();
|
||||
const fetchImpl = options.fetchImpl || fetch;
|
||||
const authService = options.authService || defaultAuthService;
|
||||
|
||||
router.use(express.json({ limit: '1mb' }));
|
||||
|
||||
router.post('/client/sign-in', async (req, res, next) => {
|
||||
try {
|
||||
const payload = authService.parseClientSignIn(req.body);
|
||||
const session = await authService.signInClient(payload, { fetchImpl });
|
||||
return res.status(200).json({
|
||||
...session,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/client/sign-up', async (req, res, next) => {
|
||||
try {
|
||||
const payload = authService.parseClientSignUp(req.body);
|
||||
const session = await authService.signUpClient(payload, { fetchImpl });
|
||||
return res.status(201).json({
|
||||
...session,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/session', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const session = await authService.getSessionForActor(req.actor);
|
||||
return res.status(200).json({
|
||||
...session,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/sign-out', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const result = await authService.signOutActor(req.actor);
|
||||
return res.status(200).json({
|
||||
...result,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/client/sign-out', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const result = await authService.signOutActor(req.actor);
|
||||
return res.status(200).json({
|
||||
...result,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/staff/sign-out', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const result = await authService.signOutActor(req.actor);
|
||||
return res.status(200).json({
|
||||
...result,
|
||||
requestId: req.requestId,
|
||||
});
|
||||
} catch (error) {
|
||||
return next(error);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
Reference in New Issue
Block a user