# Testing Authentication Endpoints This guide provides step-by-step instructions for testing the Attune authentication system. ## Prerequisites 1. **Database Running** ```bash # Start PostgreSQL (if using Docker) docker run -d \ --name postgres \ -e POSTGRES_PASSWORD=postgres \ -p 5432:5432 \ postgres:15 ``` 2. **Database Setup** ```bash # Create database and user psql -U postgres -c "CREATE DATABASE attune;" psql -U postgres -c "CREATE USER svc_attune WITH PASSWORD 'attune_password';" psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE attune TO svc_attune;" ``` 3. **Run Migrations** ```bash export DATABASE_URL="postgresql://svc_attune:attune_password@localhost:5432/attune" sqlx migrate run ``` 4. **Set Environment Variables** ```bash export DATABASE_URL="postgresql://svc_attune:attune_password@localhost:5432/attune" export JWT_SECRET="my-super-secret-jwt-key-min-256-bits-please" export JWT_ACCESS_EXPIRATION=3600 export JWT_REFRESH_EXPIRATION=604800 export RUST_LOG=info ``` ## Starting the API Server ```bash cd attune cargo run --bin attune-api ``` Expected output: ``` INFO Starting Attune API Service INFO Configuration loaded successfully INFO Environment: development INFO Connecting to database... INFO Database connection established INFO JWT configuration initialized INFO Starting server on 127.0.0.1:8080 INFO Server listening on 127.0.0.1:8080 INFO Attune API Service is ready ``` ## Testing with cURL ### 1. Health Check (Verify Server is Running) ```bash curl http://localhost:8080/api/v1/health ``` Expected response: ```json { "status": "healthy" } ``` ### 2. Register a New User ```bash curl -X POST http://localhost:8080/auth/register \ -H "Content-Type: application/json" \ -d '{ "login": "alice", "password": "securepass123", "display_name": "Alice Smith" }' ``` Expected response: ```json { "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600 } } ``` **Save the access_token for the next steps!** ### 3. Login with Existing User ```bash curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{ "login": "alice", "password": "securepass123" }' ``` Expected response: ```json { "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600 } } ``` ### 4. Get Current User (Protected Endpoint) Replace `YOUR_ACCESS_TOKEN` with the actual token from step 2 or 3: ```bash curl http://localhost:8080/auth/me \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` Expected response: ```json { "data": { "id": 1, "login": "alice", "display_name": "Alice Smith" } } ``` ### 5. Change Password (Protected Endpoint) ```bash curl -X POST http://localhost:8080/auth/change-password \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "current_password": "securepass123", "new_password": "newsecurepass456" }' ``` Expected response: ```json { "data": { "success": true, "message": "Password changed successfully" } } ``` ### 6. Login with New Password ```bash curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{ "login": "alice", "password": "newsecurepass456" }' ``` Should return new tokens. ### 7. Refresh Access Token Save the refresh_token from a previous login, then: ```bash curl -X POST http://localhost:8080/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "YOUR_REFRESH_TOKEN" }' ``` Expected response: ```json { "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600 } } ``` ## Error Cases to Test ### Invalid Credentials ```bash curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{ "login": "alice", "password": "wrongpassword" }' ``` Expected response (401): ```json { "error": "Invalid login or password", "code": "UNAUTHORIZED" } ``` ### Missing Authentication Token ```bash curl http://localhost:8080/auth/me ``` Expected response (401): ```json { "error": { "code": 401, "message": "Missing authentication token" } } ``` ### Invalid Token ```bash curl http://localhost:8080/auth/me \ -H "Authorization: Bearer invalid.token.here" ``` Expected response (401): ```json { "error": { "code": 401, "message": "Invalid authentication token" } } ``` ### Duplicate Registration Register the same user twice: ```bash curl -X POST http://localhost:8080/auth/register \ -H "Content-Type: application/json" \ -d '{ "login": "alice", "password": "securepass123" }' ``` Expected response (409): ```json { "error": "Identity with login 'alice' already exists", "code": "CONFLICT" } ``` ### Validation Errors Short password: ```bash curl -X POST http://localhost:8080/auth/register \ -H "Content-Type: application/json" \ -d '{ "login": "bob", "password": "short" }' ``` Expected response (422): ```json { "error": "Invalid registration request: ...", "code": "VALIDATION_ERROR" } ``` ## Testing with HTTPie (Alternative) If you prefer HTTPie (more readable): ```bash # Install HTTPie pip install httpie # Register http POST localhost:8080/auth/register \ login=alice password=securepass123 display_name="Alice Smith" # Login http POST localhost:8080/auth/login \ login=alice password=securepass123 # Get current user (set TOKEN variable first) TOKEN="your_access_token_here" http GET localhost:8080/auth/me \ "Authorization: Bearer $TOKEN" # Change password http POST localhost:8080/auth/change-password \ "Authorization: Bearer $TOKEN" \ current_password=securepass123 \ new_password=newsecurepass456 ``` ## Testing with Postman 1. **Import Collection** - Create a new collection named "Attune Auth" - Add base URL variable: `{{baseUrl}}` = `http://localhost:8080` 2. **Setup Environment** - Create environment "Attune Local" - Variables: - `baseUrl`: `http://localhost:8080` - `accessToken`: (will be set by tests) - `refreshToken`: (will be set by tests) 3. **Add Requests** - POST `{{baseUrl}}/auth/register` - POST `{{baseUrl}}/auth/login` - GET `{{baseUrl}}/auth/me` with header: `Authorization: Bearer {{accessToken}}` - POST `{{baseUrl}}/auth/change-password` - POST `{{baseUrl}}/auth/refresh` 4. **Test Scripts** Add to login/register requests to save tokens: ```javascript pm.test("Status is 200", function () { pm.response.to.have.status(200); }); var jsonData = pm.response.json(); pm.environment.set("accessToken", jsonData.data.access_token); pm.environment.set("refreshToken", jsonData.data.refresh_token); ``` ## Automated Testing ### Unit Tests Run the authentication unit tests: ```bash # Test password hashing cargo test --package attune-api password # Test JWT utilities cargo test --package attune-api jwt # Test middleware cargo test --package attune-api middleware # Run all API tests cargo test --package attune-api ``` ### Integration Tests (Future) Integration tests will be added to test the full authentication flow: ```bash cargo test --package attune-api --test auth_integration ``` ## Troubleshooting ### Server Won't Start 1. **Database Connection Error** ``` Error: error communicating with database ``` - Verify PostgreSQL is running - Check DATABASE_URL is correct - Verify database exists and user has permissions 2. **Migration Error** ``` Error: migration version not found ``` - Run migrations: `sqlx migrate run` 3. **JWT_SECRET Warning** ``` WARN JWT_SECRET not set, using default ``` - Set JWT_SECRET environment variable ### Authentication Fails 1. **Invalid Credentials** - Verify password is correct - Check if identity exists in database: ```sql SELECT * FROM attune.identity WHERE login = 'alice'; ``` 2. **Token Expired** - Use the refresh token to get a new access token - Check JWT_ACCESS_EXPIRATION setting 3. **Invalid Token Format** - Ensure Authorization header format: `Bearer ` - No extra spaces or quotes ### Database Issues Check identities in database: ```sql -- Connect to database psql -U svc_attune -d attune -- View all identities SELECT id, login, display_name, created FROM attune.identity; -- Check password hash exists SELECT login, attributes->>'password_hash' IS NOT NULL as has_password FROM attune.identity; ``` ## Security Notes - **Never use default JWT_SECRET in production** - Always use HTTPS in production - Store tokens securely on the client side - Implement rate limiting on auth endpoints (future) - Consider adding MFA for production (future) ## Next Steps After validating authentication works: 1. Test Pack Management API with authentication 2. Implement additional CRUD APIs 3. Add RBAC permission checking (Phase 2.13) 4. Add integration tests 5. Implement token revocation for logout ## Resources - [Authentication Documentation](./authentication.md) - [API Documentation](../README.md) - [JWT.io](https://jwt.io) - JWT token decoder/debugger