[Regression on closed #553] Still no logout endpoint — the httpOnly `access_token` cookie cannot be cleared by any client
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 59/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- authentication
Hướng nghiên cứu
Start with src/auth/auth.controller.ts and read how githubCallback() sets the access_token cookie, then check src/auth/strategies/jwt.strategy.ts to confirm how requests authenticate from cookies. Add a logout route that clears the cookie with matching attributes, and cover it in auth.controller.spec.ts and test/auth.e2e-spec.ts. Done means the cookie is cleared and a cookie-only request to /auth/me returns 401 afterward.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Location
src/auth/auth.controller.ts:61-67—AuthController.githubCallback()sets the cookiesrc/auth/auth.controller.ts— nologoutroute exists anywhere in the controllersrc/auth/strategies/jwt.strategy.ts:14-33—cookieExtractoraccepts that cookie on every request
Problem
The OAuth callback issues a session cookie:
res.cookie('access_token', accessToken, {
httpOnly: true,
secure: isProd,
sameSite: 'lax',
maxAge: 7 * 24 * 60 * 60 * 1000,
path: '/',
});
grep -rni 'logout\|clearCookie' src/ returns nothing. There is no POST /auth/logout, no res.clearCookie('access_token') call, and AuthController exposes only github, github/callback, handoff, exchange and me.
Because the cookie is httpOnly, frontend JavaScript cannot delete it either — that is the entire point of the flag. The only parties who can clear it are the server (which offers no route) and the user manually, through browser devtools or by clearing site data.
This is closed issue #553, unchanged.
Why it matters
JwtStrategy is configured to accept the token from either the Authorization header or the cookie (jwt.strategy.ts:42-45). So "signing out" in the frontend — discarding the bearer token it received from POST /auth/handoff — does not end the session at all: every subsequent request from that browser still carries the cookie, cookieExtractor finds it, and the user remains fully authenticated for the cookie's entire 7-day maxAge.
Concretely:
- On a shared or public machine, a user who clicks "Sign out" and walks away leaves a live session behind. The next person to open the site is authenticated as them and can read
GET /auth/me,GET /users, and — depending on the roles on that account — reach the money-moving routes under/bounties,/escrowand/milestones. - There is also no JWT revocation mechanism (closed #10 / #341, still unaddressed), so there is no server-side way to invalidate the token even administratively. The cookie plus the absence of revocation means a session genuinely cannot be ended for seven days by any means available to the product.
- The cookie's
maxAgeis a hard-coded 7 days independent ofJWT_EXPIRES_IN(closed #552), so shortening the JWT lifetime does not shorten the window either — it just produces a cookie that is present but rejected, with no way to remove it.
Reproduction / failure path
- Complete GitHub OAuth in a browser; confirm the
access_tokencookie is set (DevTools -> Application -> Cookies). - In the frontend, sign out (or simply clear
localStorage/sessionStorage— whatever holds the bearer token). - With no
Authorizationheader, requestGET /api/auth/mefrom the same browser. - Observed: HTTP 200 with
{ userId, username }— still authenticated. Expected: 401. - Confirm there is no way to fix this from the client:
document.cookie = 'access_token=; Max-Age=0'has no effect, because the cookie ishttpOnly.
Suggested fix
Add an authenticated logout route to AuthController that clears the cookie with the same attributes it was set with (Express only matches path/domain/sameSite/secure when clearing; a mismatch silently leaves the cookie in place):
@Post('logout')
@HttpCode(204)
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
logout(@Res({ passthrough: true }) res: Response) {
const isProd = this.configService.get('env', { infer: true }) === 'production';
res.clearCookie('access_token', {
httpOnly: true,
secure: isProd,
sameSite: 'lax',
path: '/',
});
}
Consider not requiring JwtAuthGuard on this route (or catching the 401): a user whose token has already expired should still be able to clear the stale cookie, and a logout that 401s is a confusing dead end. A separate unguarded POST /auth/logout that only ever clears the cookie is harmless — it grants nothing.
Derive the cookie's maxAge from the configured JWT_EXPIRES_IN rather than hard-coding 7 days (closed #552), so the cookie and the token it carries expire together.
Add an auth.controller.spec.ts case asserting clearCookie is called with the matching attribute set, and a test/auth.e2e-spec.ts case asserting that GET /auth/me returns 401 after POST /auth/logout when the request carries only the cookie.
- Ngôn ngữ chính
- TypeScript
- Star
- 2
- Fork
- 90
- Merge trung bình
- 31 phút
- Pull request đã merge (30 ngày)
- 20
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Không có hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của MergeFi/backend
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug security
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug testing
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug security
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của MergeFi/backend
Issue tương tự
-
ログイン中の404画面にヘッダーとナビを出すĐang mởCodex使用可 コード
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
ryuki-moro/Nicomaru#218 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
sveltejs/svelte-eslint-parser#1008 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
silverbucket/inbox-rs#351 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: The H2 series' and the H3C's fan 3 is labelled "Chamber Fan", Bambu calls it the exhaust fanĐang mởarea:ui
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug front P2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
invoicerr-app/invoicerr#964 ·
Maintainer thường phản hồi trong vòng 1 ngày