jwtService = $jwtService; } /** * Login and get tokens * * Authenticate with email and password to receive an access token and refresh token. * * @bodyParam email string required User email address. Example: user@example.com * @bodyParam password string required User password. Example: secret123 * * @response 200 { * "data": { * "id": "550e8400-e29b-41d4-a716-446655440000", * "name": "Alice Johnson", * "email": "user@example.com", * "role": "manager", * "active": true, * "created_at": "2026-01-01T00:00:00Z", * "updated_at": "2026-01-01T00:00:00Z" * }, * "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", * "refresh_token": "abc123def456", * "token_type": "bearer", * "expires_in": 3600 * } * @response 401 {"message":"Invalid credentials"} * @response 403 {"message":"Account is inactive"} * @response 422 {"errors":{"email":["The email field is required."],"password":["The password field is required."]}} */ public function login(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ 'email' => 'required|string|email', 'password' => 'required|string', ]); if ($validator->fails()) { return response()->json([ 'message' => 'Validation failed', 'errors' => $validator->errors(), ], 422); } $user = User::where('email', $request->email)->first(); if (! $user || ! Hash::check($request->password, $user->password)) { return response()->json([ 'message' => 'Invalid credentials', ], 401); } if (! $user->active) { return response()->json([ 'message' => 'Account is inactive', ], 403); } $accessToken = $this->jwtService->generateAccessToken($user); $refreshToken = $this->jwtService->generateRefreshToken($user); return (new UserResource($user))->additional([ 'access_token' => $accessToken, 'refresh_token' => $refreshToken, 'token_type' => 'bearer', 'expires_in' => $this->jwtService->getAccessTokenTTL(), ])->response(); } /** * Refresh access token * * Exchange a valid refresh token for a new access token and refresh token pair. * * @authenticated * * @bodyParam refresh_token string required Refresh token returned by login. Example: abc123def456 * * @response 200 { * "data": { * "id": "550e8400-e29b-41d4-a716-446655440000", * "name": "Alice Johnson", * "email": "user@example.com", * "role": "manager", * "active": true, * "created_at": "2026-01-01T00:00:00Z", * "updated_at": "2026-01-01T00:00:00Z" * }, * "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", * "refresh_token": "newtoken123", * "token_type": "bearer", * "expires_in": 3600 * } * @response 401 {"message":"Invalid or expired refresh token"} */ public function refresh(Request $request): JsonResponse { $refreshToken = $request->input('refresh_token'); if (empty($refreshToken)) { return response()->json([ 'message' => 'Refresh token is required', ], 422); } $userId = $this->jwtService->getUserIdFromRefreshToken($refreshToken); if (! $userId) { return response()->json([ 'message' => 'Invalid or expired refresh token', ], 401); } $user = User::find($userId); if (! $user) { return response()->json([ 'message' => 'Invalid or expired refresh token', ], 401); } $this->jwtService->invalidateRefreshToken($refreshToken, $userId); $accessToken = $this->jwtService->generateAccessToken($user); $newRefreshToken = $this->jwtService->generateRefreshToken($user); return (new UserResource($user))->additional([ 'access_token' => $accessToken, 'refresh_token' => $newRefreshToken, 'token_type' => 'bearer', 'expires_in' => $this->jwtService->getAccessTokenTTL(), ])->response(); } /** * Logout current session * * Invalidate a refresh token and end the active authenticated session. * * @authenticated * * @bodyParam refresh_token string Optional refresh token to invalidate immediately. Example: abc123def456 * * @response 200 {"message":"Logged out successfully"} */ public function logout(Request $request): JsonResponse { $user = $request->user(); $refreshToken = $request->input('refresh_token'); if ($refreshToken) { $this->jwtService->invalidateRefreshToken($refreshToken, $user?->id); } return response()->json([ 'message' => 'Logged out successfully', ]); } }