server: move Firebase auth to server-side endpoints#232
Conversation
PR Review: Server-side Firebase Authentication MigrationSummaryThis PR successfully migrates Firebase authentication from client-side SDK to server-side endpoints. The implementation is well-structured with excellent test coverage. I've identified several areas for improvement around security, error handling, and code quality. Code Quality & Architecture ✅Strengths:
Suggestions:
Security Concerns 🔒Critical Issues:
Medium Priority:
Performance Considerations ⚡
Potential Bugs 🐛
Test Coverage 🧪Excellent test coverage overall, but some gaps:
Best Practices & Recommendations 📋
Minor Issues & Nitpicks
Recommendations SummaryBefore Merge:
Post-Merge:
ConclusionThis is a solid PR that achieves its goals well. The migration to server-side auth is well-architected with good test coverage. The security issues identified are addressable, and most are standard concerns for authentication systems. With the recommended fixes, particularly around the Apple JWT generation and rate limiting, this will be production-ready. Great work on comprehensive testing and clean separation of concerns! 🎉 |
|
@codex review |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #232 +/- ##
=======================================
Coverage 76.39% 76.39%
=======================================
Files 143 143
Lines 36233 36233
=======================================
+ Hits 27680 27682 +2
+ Misses 8553 8551 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11bbdf8823
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const signature = sign.sign(privateKeyObj); | ||
|
|
||
| const r = signature.slice(0, 32); | ||
| const s = signature.slice(32, 64); | ||
| const signatureB64 = Buffer.concat([r, s]).toString('base64url'); |
There was a problem hiding this comment.
Generate a valid ES256 signature for Apple client secret
The Apple client secret generator treats crypto.sign() output as a raw 64‑byte r||s signature, but Node returns a DER‑encoded ECDSA signature by default. Slicing the DER blob into 32‑byte chunks produces an invalid JWS signature, so the resulting client secret will be rejected during Apple token exchange (Apple OAuth fails even with correct keys). Use sign.sign({ key: privateKeyObj, dsaEncoding: 'ieee-p1363' }) or a JWS helper (e.g., jose.SignJWT) to produce a proper ES256 signature.
Useful? React with 👍 / 👎.
|
@codex review |
Code Review - PR #232: Server-side Firebase Auth MigrationSummaryThis PR successfully migrates Firebase authentication from client-side SDK to server-side endpoints. The implementation is generally well-structured with comprehensive test coverage. Below are my findings organized by category. 🟢 Strengths1. Security Improvements
2. Code Quality
3. Architecture
🟡 Issues & RecommendationsHigh Priority1. Security:
|
301671a to
af73774
Compare
|
@codex review |
1 similar comment
|
@codex review |
Code Review SummaryThis is an excellent migration that moves Firebase authentication from client-side to server-side endpoints. The implementation is comprehensive with strong test coverage (2,134 lines of tests added). Here's my detailed feedback: ✅ Strengths
🔍 Issues & RecommendationsHigh Priority
Medium Priority
Low Priority
🧪 Test QualityThe test coverage is excellent with comprehensive scenarios covered:
📊 Performance Considerations
🔒 Security ConsiderationsOverall security is strong with:
📝 Recommendations for Follow-up
ConclusionThis is a well-architected PR with strong test coverage and good security practices. The main concerns are the Apple OAuth user enumeration issue and the race condition in state invalidation. Once those are addressed, this will be production-ready. Great work! 🎉 |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af737742cf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/auth/oauth-handlers.ts
Outdated
| if (!fbUser) { | ||
| logger.error('Apple user has no email and could not be found by sub'); | ||
| res.redirect('/?error=apple_no_email'); | ||
| return; |
There was a problem hiding this comment.
Allow Apple logins when email is missing
When Apple omits the email claim (which is common after the first authorization), this branch aborts unless a Firebase user with providerData for apple.com is found. But users created in this flow are created via firebaseAdmin.createUser without linking the Apple provider, so providerData will not contain apple.com and fbUser stays undefined. That means returning Apple users will be redirected to /?error=apple_no_email even though they already exist in your DB (you can match them by providerUserId). Consider falling back to the local providerUserId lookup even when no Firebase providerData entry is found, or explicitly link the Apple provider in Firebase.
Useful? React with 👍 / 👎.
|
@codex review |
Code Review SummaryThis is a well-executed migration from client-side Firebase SDK to server-side authentication endpoints. The implementation demonstrates strong security awareness with CSRF protection, URL validation, and proper token verification. However, there are several issues that should be addressed before merging. Critical Issues (Must Fix Before Merge)1. Hardcoded Firebase API KeyLocation: The Firebase API key is hardcoded: const firebaseRestClient = createFirebaseRestClient({
apiKey: 'AIzaSyConH72HQl9xOtjmYJO9o2kQ9nZZzl96G8',
emulatorHost: process.env.FIREBASE_AUTH_EMULATOR_HOST,
});Fix: Move to environment variable or config: apiKey: process.env.FIREBASE_API_KEY || config.get('authentication.firebase.apiKey'),2. Incorrect Module Import (crypto)Location: Using const crypto = require('crypto');Fix: Add at top of file: import * as crypto from 'crypto';3. Missing JWKS Refresh on Verification FailureLocation: The Apple JWKS cache has a 1-hour TTL with no fallback mechanism. If Apple rotates their signing keys, all Sign-In attempts will fail for up to an hour. Fix: Add a retry mechanism that clears cache and refetches JWKS on verification failure. High Priority Issues4. URL Validation Missing Newline Checks for Absolute URLsLocation: Newline checks only apply to relative paths, not absolute URLs. While modern Express protects against HTTP response splitting, defense-in-depth suggests checking all URL types. Fix: Perform security checks before branching on URL type: // Check for dangerous characters first
if (trimmedUrl.includes('\\') || trimmedUrl.includes('\n') || trimmedUrl.includes('\r')) {
return '/';
}
// Then check URL type
if (trimmedUrl.startsWith('/') && !trimmedUrl.startsWith('//')) {
return trimmedUrl;
}5. Code Duplication:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 67b46c8708
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (info.providerUserId) { | ||
| user = await users.findOneByScan({ providerUserId: info.providerUserId }); | ||
| } | ||
| if (!user && info.email) { | ||
| user = await users.findOneByScan({ email: info.email }); |
There was a problem hiding this comment.
Persist providerUserId when matching by email
When getOrCreateUserFromVerifiedInfo finds an existing user by email, it returns without updating providerUserId (or provider). This breaks Apple Sign In for users who first match by email: Apple only sends email on the first authorization, so subsequent Apple logins arrive without email and the callback tries to look up by providerUserId, which was never saved. That leads to /auth/apple/callback rejecting returning users with apple_no_email even though the account exists. Consider backfilling providerUserId/provider on the email-matched user so future email-less logins succeed.
Useful? React with 👍 / 👎.
|
@codex review |
Pull Request Review: Server-side Firebase Authentication MigrationOverviewThis is a substantial and well-architected PR that successfully migrates Firebase authentication from client-side SDK to server-side endpoints. The implementation is comprehensive with excellent test coverage (2,762 additions across 8 new test files). The code quality is high with proper error handling, security considerations, and clean separation of concerns. StrengthsArchitecture & Design
Security Highlights
Code Quality
Issues & Concerns🔴 Critical: Rate Limiting MissingPriority: HIGH The new authentication endpoints lack rate limiting, making them vulnerable to:
Recommendation: Implement rate limiting middleware (e.g., express-rate-limit) for all auth endpoints: import rateLimit from 'express-rate-limit';
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 requests per window for login/signup
message: 'Too many attempts, please try again later'
});
router.post('/login', authLimiter, createLoginHandler(handlerDeps));
router.post('/signup', authLimiter, createSignupHandler(handlerDeps));🟡 Security: Information Disclosure in Provider CheckFile: The
The current implementation is acceptable for internal use but should be documented. 🟡 Bug: Missing Error Handling in Client CodeFiles: Client-side auth calls lack proper error handling for non-200 responses: // Current - doesn't check response.ok
const response = await fetch('/auth/providers', { ... });
const { providers, registered } = await response.json();Fix: Add response status checks: const response = await fetch('/auth/providers', { ... });
if (!response.ok) {
const { error } = await response.json();
this.setState({ emailError: error || 'Failed to check email' });
return;
}
const { providers, registered } = await response.json();This affects all client auth calls (providers, reset-password, login, signup). 🟡 Code Quality: Hardcoded require() StatementFile: const crypto = require('crypto');Issue: Uses CommonJS import { createPrivateKey, sign } from 'crypto';This is inconsistent with the rest of the codebase and can cause bundling issues. 🟠 Potential Race Condition in JWKS CacheFile: The JWKS cache implementation has a potential race condition: async function fetchAppleJwks(): Promise<jose.JSONWebKeySet> {
const now = Date.now();
if (cachedJwks && now - jwksCacheTime < JWKS_CACHE_TTL_MS) {
return cachedJwks; // ← Multiple concurrent requests may bypass cache
}
// fetch...
}If multiple requests arrive simultaneously after cache expiration, they'll all fetch the JWKS. While not critical (just inefficient), consider using a promise-based lock pattern or accepting this as acceptable overhead. 🟠 Database Query Pattern ConcernsFile: The if (info.providerUserId) {
user = await users.findOneByScan({ providerUserId: info.providerUserId });
}
if (!user && info.email) {
user = await users.findOneByScan({ email: info.email });
// ...
}Performance consideration: Two sequential scans on every OAuth login. Consider:
The logic correctly handles the Apple email omission case (lines 188-203, oauth-handlers.ts:255-267), which is good. 🟠 Password Reset Information DisclosureFile: The password reset endpoint silently succeeds regardless of whether the email exists: try {
await deps.firebaseRestClient.sendPasswordResetEmail(email);
res.status(200).json({ success: true });
} catch (err) {
logger.error('Error sending password reset email:', err);
res.status(200).json({ success: true }); // ← Always succeeds
}Analysis: This is actually correct behavior to prevent email enumeration. However:
🟢 Minor: Deprecated Endpoint Not RemovedFile: The old // DEPRECATED: Use /auth/login instead. This endpoint exists for backward
// compatibility with existing mobile apps and will be removed in a future release.Recommendation:
This is fine for now but should have a removal plan. 🟢 Minor: Console.log in Production CodeFile: Multiple
Testing ObservationsExcellent Coverage
Edge Cases Well Covered
Performance Considerations
Recommendations SummaryMust Fix Before Merge
Should Fix Soon
Nice to Have
ConclusionThis is high-quality work that successfully achieves its goals. The architecture is solid, security considerations are mostly well-handled, and test coverage is exemplary. The critical issue is the lack of rate limiting on auth endpoints, which should be addressed before merging to production. The other issues are relatively minor and can be addressed in follow-up PRs if needed. Recommendation: ✅ Approve with required changes (add rate limiting, fix client error handling, fix require() import) Great work overall! The migration is well-designed and the test coverage gives confidence in the implementation. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 84e3ef714e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try { | ||
| await deps.firebaseAdmin.getUserByEmail(userInfo.email); | ||
| } catch (err: unknown) { | ||
| const adminErr = err as { code?: string }; | ||
| if (adminErr.code === 'auth/user-not-found') { | ||
| await deps.firebaseAdmin.createUser({ | ||
| email: userInfo.email, | ||
| displayName: userInfo.name, | ||
| photoURL: userInfo.picture, |
There was a problem hiding this comment.
Block OAuth login for disabled Firebase users
The new OAuth callbacks fetch or create a Firebase user but never check whether the fetched user is disabled, then proceed to create a local session. That means a user that has been disabled in Firebase Auth can still sign in via Google/Apple OAuth and get a valid app session, which is a regression from the previous client‑SDK flow that would reject disabled accounts. You likely want to inspect the UserRecord.disabled flag (here and in the Apple handler) and fail the login before loginUser when it’s true.
Useful? React with 👍 / 👎.
|
@codex review |
Code Review - PR #232: Server-side Firebase Authentication MigrationThis is a significant and well-executed refactoring that moves Firebase authentication from client-side to server-side. The implementation is thorough with excellent test coverage. Here's my detailed review: ✅ Strengths
🔍 Issues & ConcernsCritical Security IssueLocation: export function generateAppleClientSecret(...) {
const crypto = require('crypto'); // ⚠️ Dynamic require
// ...
}Problem: Using Fix: Move to top-level import: import * as crypto from 'crypto';Security Consideration: Password Reset Timing AttackLocation: export function createResetPasswordHandler(deps: AuthHandlerDeps): RequestHandler {
// ...
try {
await deps.firebaseRestClient.sendPasswordResetEmail(email);
res.status(200).json({ success: true });
} catch (err) {
logger.error('Error sending password reset email:', err);
res.status(200).json({ success: true }); // Always returns success
}
}Analysis: This is actually correct behavior - always returning success prevents email enumeration attacks. However, the implementation in Potential Race ConditionLocation: if (user && matchedByEmail && info.providerUserId && user.getProviderUserId() !== info.providerUserId) {
user.setProviderUserId(info.providerUserId);
user.setProvider(info.provider);
await users.update(user.getId(), {}, user); // ⚠️ Not awaited before reuse
}Problem: The updated user object is used immediately after this block without ensuring the update completed. If there's an error or race condition, subsequent operations may use stale data. Recommendation: Ensure proper error handling and consider whether the update should complete before proceeding. Minor: Inconsistent Error HandlingLocation: } catch (err) {
logger.error('Error in Google OAuth callback:', err);
await deps.stateStore.invalidate(state).catch(() => {}); // Silently ignore
res.redirect('/?error=oauth_callback_failed');
}Issue: State invalidation errors are silently ignored. While this might be intentional (best-effort cleanup), consider logging if invalidation fails to help debug state store issues. Type Safety IssueLocation: const { code, state, error, id_token: bodyIdToken, user: appleUserJson } = req.body;Problem: No runtime validation that Recommendation: Consider using a validation library (zod, yup) or add explicit type guards earlier in the handler. 📝 Code Quality Observations
🧪 Testing Observations
🎯 Performance Considerations
📋 RecommendationsMust Fix:
Should Consider:
Nice to Have:
✨ Overall AssessmentThis is a high-quality PR that demonstrates excellent security awareness and thorough testing. The architecture is clean, the code is well-organized, and the migration path is clear. The critical issue (dynamic require) is easy to fix, and the other observations are minor improvements. Recommendation: Approve with minor changes requested (fix the dynamic require). Review generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8a756486e3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const email = typeof req.body?.email === 'string' ? req.body.email.trim() : ''; | ||
| const password = typeof req.body?.password === 'string' ? req.body.password.trim() : ''; | ||
|
|
There was a problem hiding this comment.
Stop trimming passwords before auth calls
Trimming the password changes its value before it is sent to Firebase. That means users whose passwords include leading/trailing spaces (which Firebase treats as significant) will be unable to sign in, and sign-ups will create a different password than the user entered. This is a behavior regression compared to the client SDK flow, and it will surface only for passwords with whitespace at either end.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 19f5cb3b77
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return { | ||
| sub: payload.sub as string, | ||
| email: payload.email as string | undefined, | ||
| email_verified: payload.email_verified as boolean | undefined, |
There was a problem hiding this comment.
Normalize Apple email_verified before use
Apple’s ID token encodes email_verified as the string "true"/"false", but verifyAppleIdToken currently casts it to boolean without converting. This means claims.email_verified can remain a string, and when createAppleOAuthCallbackHandler passes it into firebaseAdmin.createUser (emailVerified: claims.email_verified ?? false), it will either be treated as truthy even when the string is "false" or be rejected by the Admin SDK for a non-boolean value. Either outcome can break Apple sign‑ups or incorrectly mark emails as verified. Consider explicitly mapping string values to booleans (e.g., payload.email_verified === 'true').
Useful? React with 👍 / 👎.
Code ReviewThis is a substantial and well-structured PR that migrates Firebase authentication from client-side to server-side. Overall, the implementation is solid with excellent test coverage. Here are my findings: ✅ Strengths
🔴 Critical Issues1. Security: Password Field TrimmingLocation: Trimming passwords changes the actual password. If a user intentionally includes leading/trailing spaces, they won't be able to log in. Remove 2. Security: Manual JWT GenerationLocation: Manual JWT generation is error-prone. Use the 3. Bug: Type Assertions Without ValidationLocations: Using
|
|
@codex review |
Code Review for PR #232: Server-Side Firebase Authentication MigrationOverviewThis is a substantial and well-executed refactoring that migrates Firebase authentication from client-side SDK to server-side endpoints. The implementation is thorough with excellent test coverage (~2,600+ lines of tests across 7 new test files). The commit messages are detailed and follow the project's style guide well. Strengths1. Security Improvements ✅
2. Code Quality ✅
3. OAuth Implementation ✅
Issues & Concerns1. CRITICAL: Hardcoded Secrets Exposure Risk 🔴Location: The More importantly: The Apple private key is passed as a parameter and likely comes from config. Ensure:
2. Security: JWKS Cache Invalidation 🟡Location: The JWKS cache has a 1-hour TTL but no mechanism for manual invalidation if Apple rotates their keys early. While rare, this could cause verification failures. Recommendation:
3. Code Quality: Type Assertions Without Validation 🟡Location: Multiple type assertions ( return (await response.json()) as TokenResponse;If Google/Apple changes their API response format, this could fail silently or cause runtime errors. Recommendation: Add Zod or similar runtime validation, or at minimum check for required fields. 4. Potential Race Condition 🟡Location: The "eventual consistency" workaround for duplicate temp users is concerning. The code acknowledges this is a band-aid: // we have some eventual consistency problem where sometimes we don't
// delete the temp user when completing the sign-up flow.This suggests a deeper issue with the user creation flow that should be properly investigated and fixed rather than worked around. Recommendation: Root cause analysis - why are temp users not being deleted? Is there a missing transaction or error path? 5. Error Handling: Silent Failures 🟡Location: Password reset always returns success, even on error: } catch (err) {
logger.error('Error sending password reset email:', err);
res.status(200).json({ success: true }); // Returns success even on error!
}While this prevents email enumeration attacks (good!), the error is only logged. Consider also:
6. Performance: Redundant Firebase Admin Calls 🟡Location: Both Google and Apple OAuth handlers fetch or create the Firebase user, then separately fetch it in
7. Testing: Missing Integration Test Coverage 🟡While unit tests are excellent, I don't see end-to-end integration tests for:
The 8. Code Style: Inconsistent Async/Promise Patterns 🟢Location:
9. Minor: Magic Numbers 🟢Location: const expiresIn = 15777000; // ~6 monthsUse a named constant: 10. Documentation: Missing JSDoc 🟢Public functions lack JSDoc comments explaining parameters, return values, and potential errors. This would improve maintainability. Performance Considerations
Test Coverage AnalysisExcellent coverage across:
Missing tests:
Recommendations PriorityHigh Priority
Medium Priority
Low Priority
Security Checklist
ConclusionThis is high-quality work that significantly improves the application's architecture and security posture. The migration is well-thought-out with excellent test coverage. The main concerns are around production readiness (secret management verification, external API validation, and investigating the temp user race condition). Recommendation: Approve with minor revisions to address the high-priority items above. Great job on the detailed commit messages and comprehensive testing! 🎉 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd1713c9f7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/auth/oauth-handlers.ts
Outdated
| if (!email) { | ||
| // Apple omits email on subsequent logins. Look up user by providerUserId. | ||
| const existingUser = await deps.users.findOneByScan({ providerUserId: claims.sub }); | ||
| if (existingUser) { |
There was a problem hiding this comment.
Handle returning Apple users without email
When Apple omits the email on subsequent sign-ins, this path only attempts a providerUserId lookup and otherwise rejects the login. Existing Apple users created before this change won’t have providerUserId populated, so their first post-migration login will hit this branch and be locked out with apple_no_email. This is a regression for returning Apple users; you likely need a backfill/migration or a fallback path (e.g., link by Firebase user record or allow a one-time email-based match before requiring providerUserId).
Useful? React with 👍 / 👎.
|
@codex review |
Code Review: Server-side Firebase Authentication MigrationThis is a substantial and well-structured PR that successfully migrates Firebase authentication from client-side SDK to server-side endpoints. Overall, the code quality is high with comprehensive test coverage. Below are my detailed findings: ✅ Strengths
🐛 Potential Issues1. Race Condition in Apple OAuth - No Email Path (oauth-handlers.ts:260-296)The Apple OAuth handler has a complex fallback path when email is missing on subsequent logins. There's a potential race condition: // Line 262: First lookup by providerUserId
let existingUser = await deps.users.findOneByScan({ providerUserId: claims.sub });
// Lines 273-291: If not found, try Firebase lookup and update providerUserId
const fbUser = await deps.firebaseAdmin.getUserByProviderUid('apple.com', claims.sub);
existingUser = await deps.users.findOneByScan({ email: fbUser.email });
if (existingUser) {
existingUser.setProviderUserId(claims.sub);
await deps.users.update(existingUser.getId(), {}, existingUser);
}Problem: Between the update and login, another request could see an inconsistent state. Consider wrapping this in a transaction or using atomic updates. 2. Inconsistent Error Responses (auth-handlers.ts:198-200)} catch (err) {
logger.error('Error sending password reset email:', err);
res.status(200).json({ success: true }); // ⚠️ Returns success even on error
}Issue: Password reset always returns success (even on errors) to prevent email enumeration attacks. This is intentional for security, but:
Recommendation: Add a comment explaining why errors are suppressed for security. 3. Hard-coded Crypto Require (oauth-token-exchange.ts:74)export function generateAppleClientSecret(...): string {
const crypto = require('crypto'); // ⚠️ Should be at module level
// ...
}Issue: Fix: Move to top of file with other imports. 4. Memory Leak Risk in JWKS Cache (oauth-token-exchange.ts:135-153)let cachedJwks: jose.JSONWebKeySet | undefined;
let jwksCacheTime = 0;
const JWKS_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hourIssue: Module-level cache with no max size. While Apple's JWKS is small, this pattern could be problematic if extended. Recommendation: Consider using a proper cache library (like 5. Weak Type Safety in Firebase REST Client (firebase-rest-client.ts:88)return data as T;Issue: Type assertion without runtime validation. If Firebase changes response format, this will fail silently. Recommendation: Add runtime validation using a library like
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db27462980
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Use of this source code is governed by the Apache License, | ||
| // Version 2.0, that can be found in the LICENSE file. | ||
|
|
||
| import * as jose from 'jose'; |
There was a problem hiding this comment.
Avoid ESM-only jose import in CommonJS build
The server is compiled as CommonJS (src/server/tsconfig.json sets module: "commonjs"), but jose@6 is ESM-only. This import * as jose from 'jose' will compile to require('jose') and throw ERR_REQUIRE_ESM at runtime, preventing the auth module from loading and breaking Apple OAuth flows. Consider pinning to a CJS-compatible jose version or switching this module to dynamic import() / ESM build so the server can start.
Useful? React with 👍 / 👎.
PR Review: Server-Side Firebase Authentication MigrationThis is a comprehensive migration that moves Firebase authentication from client-side SDK to server-side endpoints. The implementation is thorough with excellent test coverage (2,760 lines of tests across 8 test files). Here's my detailed feedback: Code Quality & ArchitectureStrengths
Areas for Improvement1. Error Handling & Information DisclosureLocation: } catch (err) {
logger.error('Error sending password reset email:', err);
res.status(200).json({ success: true }); // ⚠️ Silently swallows all errors
}While this prevents email enumeration attacks (good!), it also hides legitimate errors (network issues, config problems). Consider:
2. Race Condition in Apple OAuthLocation: await deps.stateStore.invalidate(state); // Line 225
// ... lots of async operations ...
await users.update(existingUser.getId(), {}, existingUser); // Line 294If the callback processing fails after invalidating state (e.g., database error at line 294), users can't retry without restarting OAuth flow. Consider invalidating state only after successful completion or implementing idempotency. 3. Hardcoded Crypto Module ImportLocation: const crypto = require('crypto'); // ⚠️ Should be at top of fileThis should be imported at the module level for consistency and testability. 4. Potential Memory Leak in JWKS CacheLocation: let cachedJwks: jose.JSONWebKeySet | undefined;
let jwksCacheTime = 0;
const JWKS_CACHE_TTL_MS = 60 * 60 * 1000;Module-level caching works but could grow unbounded if Apple's JWKS changes frequently. Consider:
5. Password Whitespace HandlingLocation: // Login preserves password whitespace (correct)
const password = typeof req.body?.password === 'string' ? req.body.password : '';
// Signup preserves too, but displayName is trimmed
const displayName = typeof req.body?.displayName === 'string' ? req.body.displayName.trim() : '';This is correct, but consider adding validation to reject passwords that are only whitespace (security best practice). 6. Multi-Key Query ImplementationLocation:
Security ConsiderationsGood Practices Observed ✅
Security Concerns
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 792266b3c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/auth/oauth-handlers.ts
Outdated
| const returnUrl = typeof req.query.returnUrl === 'string' ? req.query.returnUrl : undefined; | ||
| const state = await deps.stateStore.create(returnUrl); |
There was a problem hiding this comment.
Bind OAuth state to session to prevent login CSRF
stateStore.create(returnUrl) generates a valid state that isn’t tied to the initiating user/session. Because the callback only checks that the state exists in Firestore, an attacker can initiate OAuth, capture their own code + state, and then trick a victim into hitting the callback URL, which logs the victim into the attacker’s account. To prevent login CSRF, persist the state in the user’s session (or a signed, HttpOnly cookie) and verify it in the callback; the same issue applies to the Apple flow.
Useful? React with 👍 / 👎.
|
@codex review |
Code Review for PR #232: Server-side Firebase Authentication MigrationSummaryThis PR migrates Firebase authentication from client-side SDK to server-side endpoints. The implementation is comprehensive and well-tested, with 4,279 additions across authentication handlers, OAuth flows, and extensive test coverage. ✅ Strengths1. Excellent Security Practices
2. Comprehensive Test Coverage
3. Thoughtful Migration Path
4. Good Code Organization
🔴 Critical Issues1. Password Reset Information Disclosure (auth-handlers.ts:185-202)export function createResetPasswordHandler(deps: AuthHandlerDeps): RequestHandler {
return async (req: Request, res: Response): Promise<void> => {
// ...
try {
await deps.firebaseRestClient.sendPasswordResetEmail(email);
res.status(200).json({ success: true });
} catch (err) {
logger.error("Error sending password reset email:", err);
res.status(200).json({ success: true }); // ⚠️ SECURITY ISSUE
}
};
}Problem: Always returning success prevents email enumeration attacks, which is good. However, the log message Recommendation: Use 2. Missing Rate LimitingNone of the auth endpoints have rate limiting implemented. This is critical for:
Recommendation: Add express-rate-limit middleware to all auth routes, especially login/signup. 3. Hardcoded mock-client-secret in Tests (oauth-handlers.test.ts:14)generateAppleClientSecret: jest.fn(() => "mock-client-secret"),While this is in test code, it is a potential security smell if this value ever leaked into production code. Consider using a more obviously fake value like 🟡 High Priority Issues4. Potential Timing Attack in State Validation (oauth-handlers.ts:119-124)const sessionState = (req.session as Record<string, unknown>)?.oauthState;
if (sessionState \!== state) {
res.status(400).json({ error: "State mismatch - possible CSRF attack" });
return;
}Problem: String comparison using Recommendation: Use 5. Session State Not Cleared on Error PathsIn both Google and Apple OAuth callbacks, if an error occurs after state validation but before the Recommendation: Move the session cleanup to a finally block or earlier in the flow. 6. Apple Client Secret Long Expiration (oauth-token-exchange.ts:76)const expiresIn = 15777000; // ~6 monthsProblem: 6 months is quite long. If the secret is compromised, it could be used for an extended period. Recommendation: Consider reducing to 24-48 hours with automatic regeneration. 7. Missing Input ValidationSeveral handlers do not validate input beyond basic type checking:
Recommendation: Add validation using a library like 8. Insufficient Error Information for DebuggingWhen errors occur, users are redirected with generic error codes like Recommendation: Consider adding error IDs that can be correlated with logs for debugging. 🟢 Medium Priority Issues9. JWKS Cache Never Invalidates on Error (oauth-token-exchange.ts:135-153)If fetching JWKS fails, the cached JWKS could be stale. The cache only checks TTL, not if the previous fetch failed. Recommendation: Clear cache on fetch failure or add retry logic. 10. Inconsistent Error Handling Between ProvidersGoogle OAuth uses Recommendation: Consider extracting common user lookup/creation logic into a shared function. 11. Magic Strings for Provider NamesProvider names are scattered as string literals ( Recommendation: Define constants or use the 12. Firestore Multi-Key Query Limitation (table-firestore.ts:70-87)The implementation chains multiple Recommendation: Document the need for composite indexes in deployment docs, or add index configuration files. 13. Session Type SafetyMultiple places cast Recommendation: Extend the session type properly using module augmentation. 🔵 Minor Issues / Nitpicks14. Inconsistent Error LoggingSome errors use 15. Bundle Size Claims Not VerifiedThe PR description claims 80-200KB savings but does not include measurement evidence. Consider adding bundle size reporting to CI. 16. Missing JSDoc CommentsPublic functions lack documentation. Consider adding JSDoc for better IDE support. 🧪 Test Coverage AssessmentExcellent coverage with tests for:
Missing tests:
📊 Performance ConsiderationsPositive:
Concerns:
🔒 Security Summary
🎯 Recommendations PriorityMust Fix Before Merge:
Should Fix Soon:
Nice to Have:
✅ ConclusionThis is a high-quality PR with excellent security fundamentals, comprehensive test coverage, and thoughtful edge case handling. The authentication migration is well-architected and demonstrates strong security awareness. The critical issues identified (rate limiting, timing attacks, session cleanup) should be addressed before production deployment, but they do not block the core functionality from working correctly. Recommendation: ✅ Approve with required changes - Address the "Must Fix" items, then this is ready to merge. Great work on the thorough implementation and test coverage! 🎉 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 926822e389
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/auth/oauth-handlers.ts
Outdated
| // Verify state matches what was stored in session to prevent login CSRF | ||
| const sessionState = (req.session as Record<string, unknown>)?.oauthState; | ||
| if (sessionState !== state) { | ||
| res.status(400).json({ error: 'State mismatch - possible CSRF attack' }); |
There was a problem hiding this comment.
Avoid state checks that require same-site cookies
These callbacks require req.session.oauthState to match the incoming state, but the session cookie is configured as sameSite: "strict" in production (config/production.json) and defaults to Lax otherwise. Browsers won’t send that cookie on cross-site OAuth redirects (Apple’s form_post and Google’s redirect), so sessionState will be undefined and the handler will return 400 even when the Firestore state is valid. That makes OAuth login fail in production unless SameSite is relaxed or the CSRF check is moved entirely to the Firestore state record.
Useful? React with 👍 / 👎.
src/server/authn.ts
Outdated
| if (user && matchedByEmail && info.providerUserId && user.getProviderUserId() !== info.providerUserId) { | ||
| // User was found by email but has different (or no) providerUserId. | ||
| // Update to use the new provider info so future logins without email work. | ||
| user.setProviderUserId(info.providerUserId); | ||
| user.setProvider(info.provider); | ||
| await users.update(user.getId(), {}, user); |
There was a problem hiding this comment.
Preserve existing provider IDs when linking accounts
When a user is matched by email, this code overwrites the stored providerUserId and provider with the latest OAuth provider. That breaks Apple re-login: Apple often omits email after the first login, and the Apple callback path only searches by providerUserId/provider. If the user later signs in with Google, this overwrite removes the Apple sub, so subsequent Apple logins (without email) won’t find the account and will fail with apple_no_email despite the account existing.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e0f947411
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/authn.ts
Outdated
| if (user && matchedByEmail && info.providerUserId && !user.getProviderUserId()) { | ||
| // User was found by email but has no providerUserId set. | ||
| // Update to use the new provider info so future logins without email work. | ||
| // Only do this if the user doesn't already have a providerUserId - we don't | ||
| // want to overwrite an existing provider link as that would break re-login |
There was a problem hiding this comment.
Update providerUserId on email match even if set
When an existing user is matched by email, this code only updates providerUserId if it is empty. For users created via password signup, providerUserId is already set to the Firebase UID, so an Apple OAuth login (first time with email) will not store the Apple sub. On the next Apple login, Apple often omits email and the callback searches by providerUserId + provider (oauth-handlers.ts lines 260-264), which will miss and end in apple_no_email. This breaks Apple re-login for users who signed up with password then use Apple. Consider updating the provider link when the existing provider differs or storing multiple provider IDs.
Useful? React with 👍 / 👎.
Pull Request ReviewSummaryThis PR migrates Firebase authentication from client-side SDK to server-side endpoints, which is a significant architectural improvement. The implementation adds comprehensive auth endpoints, OAuth handlers, and extensive test coverage. Overall, this is well-structured code, but I've identified several areas for improvement. Strengths✅ Excellent Test Coverage: 2,795 lines of tests across 8 test files demonstrates strong commitment to quality Critical Issues1. Security: Apple Client Secret Generation Uses Node.js crypto Instead of jose (oauth-token-exchange.ts:74)The generateAppleClientSecret function uses require('crypto') instead of the jose library that's already in use. This is inconsistent and potentially problematic. Recommendation: Use the jose library's SignJWT for consistency and better maintainability. 2. Race Condition in OAuth State Invalidation (oauth-handlers.ts:118, 225)Both Google and Apple OAuth callbacks invalidate the state BEFORE the token exchange completes. If the token exchange fails, the state is already consumed, preventing retry. Recommendation: Invalidate state only AFTER successful completion of the entire flow, or in the catch block to prevent replay attacks even on failure. 3. Inconsistent Error Handling in Password Reset (auth-handlers.ts:185-202)The password reset handler swallows errors and always returns success. While this prevents email enumeration attacks (good!), the logged error still occurs for non-existent emails. The firebase-rest-client already handles this (line 134), so the outer catch is redundant. Recommendation: Remove the outer try-catch since the client already handles EMAIL_NOT_FOUND gracefully. Major Issues4. Missing Input Validation on OAuth returnUrl Query Parameter (oauth-handlers.ts:67, 175)The returnUrl is accepted from query params without size limits. An attacker could provide an extremely long URL that gets stored in Firestore, potentially causing DoS or excessive storage costs. Recommendation: Add length validation (e.g., max 2048 characters) before storing. 5. Apple OAuth: Complex providerUserId Lookup Logic (oauth-handlers.ts:261-309)The fallback logic for handling users without providerUserId is quite complex with nested try-catches and multiple database lookups. Recommendation: Consider adding a data migration script to backfill providerUserId for existing Apple users, then simplify this logic. Document the migration path in code comments if this must remain. 6. Console.log Used for Debugging (authn.ts:281, Login.tsx:126, 145, 235)Multiple console.log statements remain in the code. Recommendation: Replace with proper logger calls (winston) on the server and a proper error reporting mechanism on the client. 7. JWKS Cache Never Cleared on Failure (oauth-token-exchange.ts:135-153)If fetching Apple's JWKS fails, the cached JWKS could become stale indefinitely. Recommendation: Clear cache on verification failures or implement a shorter TTL for failed refreshes. Minor Issues8. Type Safety: Any Types in Passport Integration (authn.ts:279-300)Passport callbacks use any types extensively. Consider defining proper types for serialized user objects. 9. Potential Memory Leak: JWKS Cache Never Expires (oauth-token-exchange.ts:135)The JWKS cache is module-level and never cleared, even after hours of inactivity. Consider using a proper cache library with TTL support. 10. Missing Rate Limiting on Auth EndpointsThe new auth endpoints lack rate limiting, which could be abused for brute force attacks, email enumeration, and DoS. Recommendation: Add rate limiting middleware (e.g., express-rate-limit) to all auth endpoints. 11. Duplicate loginUser Function (auth-handlers.ts:40, oauth-handlers.ts:52)The same loginUser helper appears in both files with identical implementation. Recommendation: Extract to a shared utility module. 12. URL Validation: Backslash Check (url-validation.ts:22-24)Add a comment explaining why both checks are needed, or consolidate if one is sufficient. Code Quality ObservationsGood Patterns:
Suggestions:
TestingThe test coverage is excellent overall. A few suggestions:
Performance Considerations✅ Good: Removing Firebase SDK from client bundle is a significant win Security AssessmentOverall security posture is strong:
VerdictThis is solid work with good architecture and excellent test coverage. The critical issues should be addressed before merge, particularly:
The other issues are important but could be addressed in follow-up PRs if time is constrained. Recommendation: Approve with required changes to items 1-3 above. Great work on this migration! The move to server-side auth is the right architectural decision, and the implementation quality is high overall. |
|
@codex review |
Code Review - PR #232: Server-side Firebase Auth MigrationThis is a substantial and well-executed refactoring that migrates Firebase authentication from client-side SDK to server-side endpoints. The PR demonstrates strong engineering practices with comprehensive test coverage (2800+ lines of tests) and thoughtful iterative improvements through 16 commits. ✅ Strengths1. Excellent Test Coverage
2. Strong Security Implementation
3. Well-Structured Code
4. Thoughtful Migration Path
5. Performance Improvements
🔍 Issues & RecommendationsCritical Issues1. Password Trimming Inconsistency in Client File: The server correctly preserves password whitespace (commit 19f5cb3), but the client still trims passwords in signup/login. Users cannot create/use passwords with leading/trailing spaces, creating an inconsistency with the server's handling. Recommendation: Remove High Priority Issues2. Race Condition in OAuth State Invalidation File: State is invalidated after validation but before the user is logged in. If token exchange or user creation fails after state invalidation, the state is consumed but the user isn't logged in. Recommendation: Move 3. Session Fixation Vulnerability File:
Recommendation: Regenerate the session before calling 4. Email Verification Not Enforced File: The Recommendation: Either enforce Medium Priority Issues5. Missing Rate Limiting The auth endpoints don't appear to have rate limiting beyond Firebase's built-in Recommendation: Add express-rate-limit middleware to prevent brute force attacks on 6. Insufficient Logging for Security Events Failed logins, disabled account attempts, and suspicious OAuth callbacks should be logged for security monitoring. Recommendation: Add structured logging for failed login attempts, disabled account access attempts, OAuth state validation failures, and suspicious redirect URLs. 7. Type Safety Issue with File: Passport serialization uses 8. Apple Client Secret Regeneration Overhead File: The Apple client secret is regenerated on every callback (valid for 6 months but recreated each time). Performance impact is negligible, but unnecessarily re-signing. Recommendation: Cache the client secret with a TTL (e.g., 1 day). 9. Inconsistent Error Handling in Password Reset File: Password reset always returns success even on error (for security), but logs the error. This is correct for preventing email enumeration, but the Recommendation: Only catch Low Priority / Nitpicks10. Magic Strings for Providers
11. Unclear Variable Name File:
12. Duplicate Code in OAuth Handlers Google and Apple handlers share significant logic for Firebase user lookup/creation and disabled checks. Extract shared logic into helper functions to reduce duplication and maintain consistency. 13. Missing JSDoc Comments Public functions lack documentation explaining parameters, return values, and error conditions. Add JSDoc for public APIs, especially 🎯 Best Practices & ArchitecturePositive:
Suggestions:
📊 Performance ConsiderationsPositive:
Watch Out For:
🔐 Security Summary
📝 RecommendationOverall Assessment: This is high-quality work with excellent test coverage and security fundamentals. The migration is well-thought-out and handles edge cases thoroughly. Status: ✅ Approve with Required Changes Required Before Merge:
Recommended for Follow-up PR:
Great work on this complex migration! The iterative approach through 16 commits shows careful attention to edge cases and security concerns. Note: Review based on CLAUDE.md guidelines and TypeScript/Rust development standards for the Simlin project. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff3f786a73
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/server/auth/oauth-handlers.ts
Outdated
| } catch { | ||
| // If we can't find the Firebase user, proceed with login | ||
| // (the user might not have been created via Firebase) | ||
| } |
There was a problem hiding this comment.
Prevent disabled Apple users from bypassing checks
In the no-email Apple path, a failed getUserByProviderUid lookup is silently ignored and the handler proceeds to log the user in. This means an account that was disabled in Firebase but lacks an Apple provider link (e.g., created via createUser during first Apple login) can still authenticate on subsequent logins when Apple omits the email. Consider falling back to getUserByEmail(existingUser.getEmail()) or otherwise enforcing the disabled check before calling loginUser.
Useful? React with 👍 / 👎.
|
@codex review |
Code Review: Server-Side Firebase Authentication MigrationThis is a well-executed migration from client-side to server-side Firebase authentication. The implementation demonstrates strong security practices and comprehensive test coverage. Below are my findings organized by category. ✅ StrengthsSecurity Architecture
Code Quality
Implementation Details
|
|
Codex Review: Didn't find any major issues. You're on a roll. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
8cd08bd to
3383c05
Compare
Code ReviewFinding 1: [P2] Missing
|
Code ReviewThis is a well-structured migration from client-side Firebase auth to server-side endpoints. The iterative commit history shows thoughtful handling of edge cases (Apple no-email, disabled users, provider-scoped lookups, password whitespace preservation). The security measures — Firestore-backed state tokens, URL validation, JWKS verification, anti-enumeration on password reset — are solid. After thorough review of all 18 commits and the final state of all changed files, I found no blocking bugs. Here are the findings: [P3]
|
Code Review: server: move Firebase auth to server-side endpointsI reviewed the full diff covering auth handlers, OAuth flows (Google + Apple), Firebase REST client, URL validation, OAuth state management, protobuf schema changes, Firestore query updates, and client-side migration. FindingsNo blocking bugs found. The auth flows are correctly implemented: input validation is consistent, error codes map to appropriate HTTP statuses, the password-reset handler correctly returns 200 on all paths to prevent email enumeration, and the URL validation covers the standard open-redirect attack vectors (protocol-relative URLs, One observation worth noting: [P3] Cross-provider login edge case with Apple email omission If a user originally signed up via Google (old or new flow) and later logs in with Apple, the first Apple login succeeds (Apple provides email). On subsequent Apple logins, Apple may omit the email. At that point Overall Correctness VerdictCorrect. The patch is well-structured with clean dependency injection, comprehensive tests, and appropriate error handling. Existing code and tests should not break, and the migration path (deprecated |
Code Review[P2]
|
Review cycle summaryFour iterations of automated review (codex + Claude) identified and resolved several improvements to the auth migration: Fixes applied:
Issues tracked for follow-up: #380 (email enumeration rate limiting), #381 (Firebase API key to config), #382 (deprecated passport removal), #383 (CSP frame-src cleanup), #384 (OAuth button visibility), #385 (Apple OAuth nonce), #386 (Firestore composite index). |
991d059 to
5dffc13
Compare
Code Review[P1] TOCTOU race in OAuth state validation allows state token replayFile:
[P2] Unrecognized Firebase error codes leak raw error messages to the clientFile:
[P2]
|
94a2ea5 to
c5f17c2
Compare
Code ReviewI've reviewed the full diff for this PR (moving Firebase auth from client-side SDK to server-side endpoints). The changes span the client-side login flow, new server auth handlers, OAuth flows for Google and Apple, URL validation, Firestore-backed OAuth state, and protobuf schema extension. FindingsNo bugs found that meet the review criteria. NotesThe implementation looks solid:
Overall Correctness VerdictCorrect. The patch is free of bugs and blocking issues. Existing code and tests should not break. |
Code Review[P1] TOCTOU race in OAuth state validation allows token replayFile:
[P2]
|
c5f17c2 to
fe4c024
Compare
Code Review: server: move Firebase auth to server-side endpointsI reviewed all 31 changed files (~4,500 additions) covering the migration from client-side Firebase SDK authentication to server-side auth endpoints. ArchitectureThe migration is well-structured:
SecurityThe security posture is solid:
Edge CasesThe Apple Sign-In "no email on subsequent logins" case is handled well via The provider migration logic in FindingsNo bugs found. The code is correct, well-tested, and handles the numerous edge cases in OAuth authentication appropriately. Overall Correctness VerdictCorrect. Existing code and tests will not break. The migration is clean — existing server sessions (Passport + seshcookie) remain the source of truth, so users with valid session cookies will stay logged in after deployment. The new protobuf field ( |
Migrate Firebase authentication from client-side SDK to server-side endpoints that call the Firebase REST API. This reduces client bundle size by removing the Firebase SDK dependencies (~80-200KB) and enables future migration to alternative auth backends. The implementation includes: - Email/password auth endpoints (/auth/login, /auth/signup, etc.) - OAuth handlers for Google and Apple Sign-In with full server-side token exchange - Firestore-backed OAuth state storage for CSRF protection - Full cryptographic verification of Apple ID tokens using JWKS - Return URL validation to prevent open redirect attacks - User protobuf schema extended with providerUserId for stable OAuth provider identity Client code now uses simple redirects for OAuth and fetch calls for email/password auth, with all Firebase SDK code removed.
fe4c024 to
fec5fc6
Compare
Code ReviewI reviewed this PR thoroughly, focusing on security, correctness, and the interaction between new and existing code. SummaryThis is a well-structured migration of Firebase authentication from client-side SDK to server-side endpoints. The implementation demonstrates careful attention to security:
FindingsNo bugs found. The code handles the security-sensitive OAuth and authentication flows correctly. Edge cases like Apple omitting email on subsequent logins, duplicate temp-user recovery, and provider migration (password → OAuth) are handled with appropriate care. Overall Correctness VerdictCorrect. The patch is free of bugs and blocking issues. Existing code and tests should not break — the old client-side Firebase SDK usage and the |
Summary
/auth/login,/auth/signup,/auth/providers,/auth/reset-password,/auth/logout)providerUserIdfor stable OAuth identityTest plan
pnpm --filter @system-dynamics/server testto verify all new auth tests passGenerated with Claude Code