db = \Config\Database::connect(); } /** * Check authentication status * GET /v2/auth/check */ public function checkAuth() { $token = $this->request->getCookie('token'); $key = getenv('JWT_SECRET'); if (!$token) { return $this->respond([ 'status' => 'failed', 'message' => 'No token found' ], 401); } try { $decodedPayload = JWT::decode($token, new Key($key, 'HS256')); return $this->respond([ 'status' => 'success', 'message' => 'Authenticated', 'data' => $decodedPayload ], 200); } catch (ExpiredException $e) { return $this->respond([ 'status' => 'failed', 'message' => 'Token expired' ], 401); } catch (SignatureInvalidException $e) { return $this->respond([ 'status' => 'failed', 'message' => 'Invalid token signature' ], 401); } catch (BeforeValidException $e) { return $this->respond([ 'status' => 'failed', 'message' => 'Token not valid yet' ], 401); } catch (\Exception $e) { return $this->respond([ 'status' => 'failed', 'message' => 'Invalid token: ' . $e->getMessage() ], 401); } } /** * Login user * POST /v2/auth/login */ public function login() { $username = $this->request->getVar('username'); $password = $this->request->getVar('password'); $key = getenv('JWT_SECRET'); // Validate username if (!$username) { return $this->respond([ 'status' => 'failed', 'message' => 'Username is required' ], 400); } // Find user $sql = "SELECT * FROM users WHERE username = " . $this->db->escape($username); $query = $this->db->query($sql); $row = $query->getResultArray(); if (!$row) { return $this->respond([ 'status' => 'failed', 'message' => 'User not found' ], 401); } $row = $row[0]; // Verify password if (!password_verify($password, $row['password'])) { return $this->respond([ 'status' => 'failed', 'message' => 'Invalid password' ], 401); } // Create JWT payload $exp = time() + 864000; // 10 days $payload = [ 'userid' => $row['id'], 'roleid' => $row['role_id'], 'username' => $row['username'], 'exp' => $exp ]; try { $jwt = JWT::encode($payload, $key, 'HS256'); } catch (\Exception $e) { return $this->respond([ 'status' => 'failed', 'message' => 'Error generating JWT: ' . $e->getMessage() ], 500); } // Detect if HTTPS is being used $isSecure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'; // Set HTTP-only cookie $this->response->setCookie([ 'name' => 'token', 'value' => $jwt, 'expire' => 864000, 'path' => '/', 'secure' => $isSecure, // false for localhost HTTP 'httponly' => true, 'samesite' => $isSecure ? Cookie::SAMESITE_NONE : Cookie::SAMESITE_LAX ]); return $this->respond([ 'status' => 'success', 'message' => 'Login successful', 'data' => [ 'username' => $row['username'], 'role_id' => $row['role_id'] ] ], 200); } /** * Logout user * POST /v2/auth/logout */ public function logout() { // Detect if HTTPS is being used $isSecure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'; // Clear the token cookie return $this->response->setCookie([ 'name' => 'token', 'value' => '', 'expire' => time() - 3600, 'path' => '/', 'secure' => $isSecure, 'httponly' => true, 'samesite' => $isSecure ? Cookie::SAMESITE_NONE : Cookie::SAMESITE_LAX ])->setJSON([ 'status' => 'success', 'message' => 'Logout successful' ]); } /** * Register new user * POST /v2/auth/register */ public function register() { $username = strtolower($this->request->getJsonVar('username')); $password = $this->request->getJsonVar('password'); // Validate input if (empty($username) || empty($password)) { return $this->respond([ 'status' => 'failed', 'message' => 'Username and password are required' ], 400); } // Check for existing username $exists = $this->db->query("SELECT id FROM users WHERE username = ?", [$username])->getRow(); if ($exists) { return $this->respond([ 'status' => 'failed', 'message' => 'Username already exists' ], 409); } // Hash password $hashedPassword = password_hash($password, PASSWORD_DEFAULT); // Insert user $this->db->transStart(); $this->db->query( "INSERT INTO users(username, password, role_id) VALUES(?, ?, ?)", [$username, $hashedPassword, 1] ); $this->db->transComplete(); if ($this->db->transStatus() === false) { return $this->respond([ 'status' => 'failed', 'message' => 'Failed to create user' ], 500); } return $this->respond([ 'status' => 'success', 'message' => 'User ' . $username . ' successfully created' ], 201); } }