diff --git a/frontend/src/types.ts b/frontend/src/types.ts index da72c1c..66b8bd3 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -14,7 +14,7 @@ export interface ErrorDto { export type Role = 'USER' | 'ADMIN' | 'BOT'; -export interface MeResponse { +export interface UserAuthDto { id: number; name: string; role: Role; diff --git a/frontend/src/useAuth.tsx b/frontend/src/useAuth.tsx index 2e023b3..be31661 100644 --- a/frontend/src/useAuth.tsx +++ b/frontend/src/useAuth.tsx @@ -1,10 +1,10 @@ import React, { createContext, useState, useContext, useEffect } from 'react'; -import { JwtResponse, MeResponse } from "@/types.ts"; +import { JwtResponse, UserAuthDto } from "@/types.ts"; interface Auth { ready: boolean; accessToken: string | null; - user: MeResponse | null; + user: UserAuthDto | null; impersonating: string | null; login: (token: string) => Promise; logout: () => Promise; @@ -18,15 +18,15 @@ const AuthContext = createContext(null); export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const [ready, setReady] = useState(false); const [accessToken, setAccessToken] = useState(null); - const [user, setUser] = useState(null); + const [user, setUser] = useState(null); const [impersonating, setImpersonating] = useState(null); - const fetchUserInfo = async (token: string): Promise => { + const fetchUserInfo = async (token: string): Promise => { const response = await fetch('/api/auth/me', { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { throw new Error('Failed to fetch user info'); } - return await response.json() as MeResponse; + return await response.json() as UserAuthDto; }; const login = async (token: string) => { @@ -39,7 +39,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const logout = async () => { try { - await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }); + await fetch('/api/auth/refresh', { method: 'DELETE', credentials: 'include' }); } catch (error) { console.error('Failed to call logout endpoint:', error); } diff --git a/src/main/java/com/icube/sim/tichu/auth/AuthController.java b/src/main/java/com/icube/sim/tichu/auth/AuthController.java index b5cfa47..fff12dc 100644 --- a/src/main/java/com/icube/sim/tichu/auth/AuthController.java +++ b/src/main/java/com/icube/sim/tichu/auth/AuthController.java @@ -37,20 +37,22 @@ public JwtResponse refresh( return new JwtResponse(jwtIssueResult.getAccessToken().toString()); } - @PostMapping("/logout") + // Mapped under /refresh (not /logout), so the refresh_token cookie, scoped to path /api/auth/refresh, + // is sent with the request. + @DeleteMapping("/refresh") public ResponseEntity<@NonNull Void> logout( @CookieValue(value = RefreshTokenCookieFactory.COOKIE_NAME, required = false) String refreshToken, HttpServletResponse response ) { - authService.logout(refreshToken); + authService.destroyRefreshToken(refreshToken); response.addCookie(refreshTokenCookieFactory.createExpired()); return ResponseEntity.noContent().build(); } @GetMapping("/me") - public MeResponse getMe() { + public UserAuthDto getMe() { var user = authService.getCurrentUser(); - return new MeResponse(user.getId(), user.getName(), user.getRole()); + return new UserAuthDto(user.getId(), user.getName(), user.getRole()); } @GetMapping("/issue/web-socket-token") diff --git a/src/main/java/com/icube/sim/tichu/auth/AuthService.java b/src/main/java/com/icube/sim/tichu/auth/AuthService.java index 44bc15c..afca8ab 100644 --- a/src/main/java/com/icube/sim/tichu/auth/AuthService.java +++ b/src/main/java/com/icube/sim/tichu/auth/AuthService.java @@ -64,7 +64,7 @@ public JwtIssueResult refreshTokens(String oldRefreshToken) { return issueTokens(user); } - public void logout(String refreshToken) { + public void destroyRefreshToken(String refreshToken) { if (refreshToken == null) { return; } diff --git a/src/main/java/com/icube/sim/tichu/auth/SecurityConfig.java b/src/main/java/com/icube/sim/tichu/auth/SecurityConfig.java index fa89124..fe9d30b 100644 --- a/src/main/java/com/icube/sim/tichu/auth/SecurityConfig.java +++ b/src/main/java/com/icube/sim/tichu/auth/SecurityConfig.java @@ -69,7 +69,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) { .authorizeHttpRequests(c -> c .requestMatchers("/error").permitAll() .requestMatchers(HttpMethod.POST, "/api/users").permitAll() - .requestMatchers(HttpMethod.POST, "/api/auth/login", "/api/auth/refresh", "/api/auth/logout").permitAll() + .requestMatchers(HttpMethod.POST, "/api/auth/login", "/api/auth/refresh").permitAll() + .requestMatchers(HttpMethod.DELETE, "/api/auth/refresh").permitAll() .requestMatchers(HttpMethod.GET, "/api/auth/social/*/url").permitAll() .requestMatchers(HttpMethod.POST, "/api/auth/social/*/login").permitAll() .requestMatchers("/api/ws").permitAll() diff --git a/src/main/java/com/icube/sim/tichu/auth/MeResponse.java b/src/main/java/com/icube/sim/tichu/auth/UserAuthDto.java similarity index 89% rename from src/main/java/com/icube/sim/tichu/auth/MeResponse.java rename to src/main/java/com/icube/sim/tichu/auth/UserAuthDto.java index ed6ecee..2e435be 100644 --- a/src/main/java/com/icube/sim/tichu/auth/MeResponse.java +++ b/src/main/java/com/icube/sim/tichu/auth/UserAuthDto.java @@ -6,7 +6,7 @@ @AllArgsConstructor @Getter -public class MeResponse { +public class UserAuthDto { private Long id; private String name; private Role role;