Skip to content

Commit f5499d2

Browse files
authored
feat: add webapp authentication endpoints (#317)
Add endpoints required for webapp proxy integration: - GET /user/logout and /api/user/logout for webapp logout flow - GET /api/auth/session to retrieve sessionId for httpOnly cookie setup - /login now accepts ?redirect parameter for post-OAuth redirection - /github-callback redirects to stored URL or /dashboard Mark POST /api/auth/logout as deprecated in favor of GET endpoints. Document the webapp integration pattern in code comments.
1 parent 7c7a7ce commit f5499d2

File tree

1 file changed

+62
-4
lines changed

1 file changed

+62
-4
lines changed

src/index.js

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,16 @@ async function startServer() {
137137
});
138138

139139
app.get('/login', function (req, res) {
140+
// Store redirect URL for webapp integration (redirect back after OAuth)
141+
if (req.query.redirect) {
142+
req.session.authRedirect = req.query.redirect;
143+
}
144+
140145
if (req.session.userId) {
141-
res.redirect('/dashboard');
146+
// Already logged in - redirect to stored URL or dashboard
147+
const redirectUrl = req.session.authRedirect || '/dashboard';
148+
delete req.session.authRedirect;
149+
res.redirect(redirectUrl);
142150
} else {
143151
// TODO use `code`, too (https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps)
144152
const redirectUri = isProduction
@@ -214,14 +222,36 @@ async function startServer() {
214222
});
215223
}
216224
req.session.userId = user._id.toString();
217-
res.redirect('/dashboard');
225+
226+
// Redirect to stored URL (webapp) or default to dashboard
227+
const redirectUrl = req.session.authRedirect || '/dashboard';
228+
delete req.session.authRedirect;
229+
res.redirect(redirectUrl);
218230
} catch (e) {
219231
console.error('GitHub OAuth error:', e);
220-
res.redirect('/');
232+
// On error, redirect to stored error URL or home
233+
const errorRedirect = req.session.authRedirect
234+
? `${req.session.authRedirect}?error=oauth_failed`
235+
: '/';
236+
delete req.session.authRedirect;
237+
res.redirect(errorRedirect);
221238
}
222239
});
223240

224-
// API Authentication endpoints (for webapp compatibility)
241+
// ============================================================================
242+
// API Authentication Endpoints
243+
// ============================================================================
244+
// Webapp Integration Pattern:
245+
// 1. Webapp redirects browser to /login?redirect=<webapp-callback-url>
246+
// 2. OAuth flow completes, user redirected back to webapp callback
247+
// 3. Webapp calls GET /api/auth/session to get sessionId
248+
// 4. Webapp sets sessionId as httpOnly cookie
249+
// 5. Subsequent requests: proxy converts cookie to SESSION header
250+
//
251+
// Deprecated endpoints (remove after webapp migration complete):
252+
// - POST /api/auth/logout -> use GET /user/logout or GET /api/user/logout
253+
// ============================================================================
254+
225255
app.get('/api/auth/status', async function (req, res) {
226256
if (!req.session.userId) {
227257
return res.status(401).json({ authenticated: false });
@@ -259,6 +289,7 @@ async function startServer() {
259289
}
260290
});
261291

292+
// @deprecated - Use GET /api/user/logout instead (webapp uses this)
262293
app.post('/api/auth/logout', function (req, res) {
263294
req.session.destroy(err => {
264295
if (err) {
@@ -269,6 +300,33 @@ async function startServer() {
269300
});
270301
});
271302

303+
// Logout endpoints for webapp compatibility
304+
// Webapp proxy intercepts /user/logout to clear httpOnly cookie
305+
const logoutHandler = function (req, res) {
306+
req.session.destroy(err => {
307+
if (err) {
308+
console.error('Session destruction error:', err);
309+
return res.status(500).json({ error: 'Failed to logout' });
310+
}
311+
res.json({ success: true });
312+
});
313+
};
314+
app.get('/user/logout', logoutHandler);
315+
app.get('/api/user/logout', logoutHandler);
316+
317+
// Session endpoint for webapp - returns sessionId for httpOnly cookie setup
318+
// Used after OAuth callback redirects back to webapp
319+
app.get('/api/auth/session', function (req, res) {
320+
if (!req.session.userId) {
321+
return res.status(401).json({ authenticated: false });
322+
}
323+
// Return the session ID so webapp can set it as httpOnly cookie
324+
res.json({
325+
authenticated: true,
326+
sessionId: req.sessionID,
327+
});
328+
});
329+
272330
app.get('/v1/user', async function (req, res) {
273331
if (!req.session.userId) {
274332
return res.status(401).end();

0 commit comments

Comments
 (0)