9.4 KiB
Testing Authentication Endpoints
This guide provides step-by-step instructions for testing the Attune authentication system.
Prerequisites
-
Database Running
# Start PostgreSQL (if using Docker) docker run -d \ --name postgres \ -e POSTGRES_PASSWORD=postgres \ -p 5432:5432 \ postgres:15 -
Database Setup
# 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;" -
Run Migrations
export DATABASE_URL="postgresql://svc_attune:attune_password@localhost:5432/attune" sqlx migrate run -
Set Environment Variables
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
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)
curl http://localhost:8080/api/v1/health
Expected response:
{
"status": "healthy"
}
2. Register a New User
curl -X POST http://localhost:8080/auth/register \
-H "Content-Type: application/json" \
-d '{
"login": "alice",
"password": "securepass123",
"display_name": "Alice Smith"
}'
Expected response:
{
"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
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{
"login": "alice",
"password": "securepass123"
}'
Expected response:
{
"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:
curl http://localhost:8080/auth/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Expected response:
{
"data": {
"id": 1,
"login": "alice",
"display_name": "Alice Smith"
}
}
5. Change Password (Protected Endpoint)
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:
{
"data": {
"success": true,
"message": "Password changed successfully"
}
}
6. Login with New Password
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:
curl -X POST http://localhost:8080/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "YOUR_REFRESH_TOKEN"
}'
Expected response:
{
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
}
Error Cases to Test
Invalid Credentials
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{
"login": "alice",
"password": "wrongpassword"
}'
Expected response (401):
{
"error": "Invalid login or password",
"code": "UNAUTHORIZED"
}
Missing Authentication Token
curl http://localhost:8080/auth/me
Expected response (401):
{
"error": {
"code": 401,
"message": "Missing authentication token"
}
}
Invalid Token
curl http://localhost:8080/auth/me \
-H "Authorization: Bearer invalid.token.here"
Expected response (401):
{
"error": {
"code": 401,
"message": "Invalid authentication token"
}
}
Duplicate Registration
Register the same user twice:
curl -X POST http://localhost:8080/auth/register \
-H "Content-Type: application/json" \
-d '{
"login": "alice",
"password": "securepass123"
}'
Expected response (409):
{
"error": "Identity with login 'alice' already exists",
"code": "CONFLICT"
}
Validation Errors
Short password:
curl -X POST http://localhost:8080/auth/register \
-H "Content-Type: application/json" \
-d '{
"login": "bob",
"password": "short"
}'
Expected response (422):
{
"error": "Invalid registration request: ...",
"code": "VALIDATION_ERROR"
}
Testing with HTTPie (Alternative)
If you prefer HTTPie (more readable):
# 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
-
Import Collection
- Create a new collection named "Attune Auth"
- Add base URL variable:
{{baseUrl}}=http://localhost:8080
-
Setup Environment
- Create environment "Attune Local"
- Variables:
baseUrl:http://localhost:8080accessToken: (will be set by tests)refreshToken: (will be set by tests)
-
Add Requests
- POST
{{baseUrl}}/auth/register - POST
{{baseUrl}}/auth/login - GET
{{baseUrl}}/auth/mewith header:Authorization: Bearer {{accessToken}} - POST
{{baseUrl}}/auth/change-password - POST
{{baseUrl}}/auth/refresh
- POST
-
Test Scripts Add to login/register requests to save tokens:
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:
# 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:
cargo test --package attune-api --test auth_integration
Troubleshooting
Server Won't Start
-
Database Connection Error
Error: error communicating with database- Verify PostgreSQL is running
- Check DATABASE_URL is correct
- Verify database exists and user has permissions
-
Migration Error
Error: migration version not found- Run migrations:
sqlx migrate run
- Run migrations:
-
JWT_SECRET Warning
WARN JWT_SECRET not set, using default- Set JWT_SECRET environment variable
Authentication Fails
-
Invalid Credentials
- Verify password is correct
- Check if identity exists in database:
SELECT * FROM attune.identity WHERE login = 'alice';
-
Token Expired
- Use the refresh token to get a new access token
- Check JWT_ACCESS_EXPIRATION setting
-
Invalid Token Format
- Ensure Authorization header format:
Bearer <token> - No extra spaces or quotes
- Ensure Authorization header format:
Database Issues
Check identities in database:
-- 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:
- Test Pack Management API with authentication
- Implement additional CRUD APIs
- Add RBAC permission checking (Phase 2.13)
- Add integration tests
- Implement token revocation for logout
Resources
- Authentication Documentation
- API Documentation
- JWT.io - JWT token decoder/debugger