# Server API Documentation ## Overview The Self identity server provides a RESTful API for email verification, user registration, and OAuth 2.0 compatible authentication. The server is built with Rust and Axum, providing high performance and security. ## Base Configuration - **Default Port**: 8080 - **Protocol**: HTTP/HTTPS - **Content-Type**: application/json - **CORS**: Enabled for cross-origin requests ## API Endpoints ### Health Check #### GET /health Health check endpoint for monitoring and load balancers. **Response:** ```json { "status": "healthy", "service": "self-server" } ``` **Status Codes:** - `200 OK`: Service is healthy --- ### Email Verification #### POST /api/send-verification Initiates email verification process for new user registration. **Request Body:** ```json { "email": "user@example.com" } ``` **Response:** ```json { "success": true, "message": "Verification email sent", "verification_url": "http://localhost:8080/api/verify/uuid-token" } ``` **Status Codes:** - `200 OK`: Verification email sent successfully - `400 Bad Request`: Invalid email format - `500 Internal Server Error`: Server error **Notes:** - In development mode, verification URL is logged to console - Production should integrate with SMTP service - Verification tokens are UUID v4 format #### GET /api/verification-status/{email} Server-Sent Events stream for real-time verification status updates. **Parameters:** - `email`: URL-encoded email address **Response:** SSE stream with events: ``` data: verified ``` **Event Types:** - `verified`: Email has been successfully verified - `keep-alive`: Periodic keep-alive message **Usage Example:** ```javascript const eventSource = new EventSource('/api/verification-status/user@example.com'); eventSource.onmessage = function(event) { if (event.data === 'verified') { // Update UI to show verified status } }; ``` #### GET /api/verify/{token} Email verification callback endpoint. Users click this link from their email. **Parameters:** - `token`: Verification token from email link **Response:** HTML page confirming verification **Status Codes:** - `200 OK`: Email verified successfully - `400 Bad Request`: Invalid or expired token **HTML Response (Success):** ```html Email Verified

Email Verified Successfully!

Your email address has been verified.

``` --- ### User Registration #### POST /api/register Completes user registration after email verification. **Request Body:** ```json { "email": "user@example.com", "name": "John Doe", "public_key": "04a1b2c3d4e5f6..." } ``` **Response:** ```json { "success": true, "message": "Registration completed successfully", "user_id": "uuid-user-id" } ``` **Error Response:** ```json { "success": false, "message": "Email not verified", "user_id": null } ``` **Status Codes:** - `200 OK`: Registration successful - `400 Bad Request`: Email not verified or invalid data - `500 Internal Server Error`: Server error **Validation:** - Email must be verified before registration - Public key must be valid hex format - Name cannot be empty --- ### OAuth 2.0 Authentication #### POST /oauth/token OAuth 2.0 token endpoint for cryptographic authentication. **Request Body:** ```json { "grant_type": "client_credentials", "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", "client_assertion": "signed-jwt-token", "public_key": "04a1b2c3d4e5f6...", "challenge": "server-challenge", "scope": "openid profile" } ``` **Response:** ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600 } ``` **Error Response:** ```json { "error": "invalid_client", "error_description": "User not found" } ``` **Status Codes:** - `200 OK`: Authentication successful - `401 Unauthorized`: Invalid credentials or signature - `400 Bad Request`: Malformed request **OAuth 2.0 Error Codes:** - `invalid_client`: Public key not found - `invalid_grant`: Invalid signature or challenge - `unsupported_grant_type`: Grant type not supported - `server_error`: Internal server error #### GET /oauth/userinfo OpenID Connect UserInfo endpoint. Returns user profile information. **Headers:** ``` Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` **Response:** ```json { "sub": "user-id", "email": "user@example.com", "name": "John Doe", "public_key": "04a1b2c3d4e5f6...", "created_at": "1640995200" } ``` **Error Response:** ```json { "error": "invalid_token", "error_description": "Missing Authorization header" } ``` **Status Codes:** - `200 OK`: User info returned successfully - `401 Unauthorized`: Invalid or missing token --- ## Data Models ### User Model ```rust struct User { id: String, // UUID v4 email: String, // Verified email address public_key: String, // Hex-encoded public key name: String, // Display name created_at: String, // Unix timestamp } ``` ### JWT Claims ```rust struct Claims { sub: String, // Subject (public key) iss: String, // Issuer ("self-sovereign-identity") aud: String, // Audience ("identity-server") exp: usize, // Expiration time (Unix timestamp) iat: usize, // Issued at time (Unix timestamp) scope: String, // Granted scopes } ``` ### Verification Status ```rust struct VerificationStatus { email: String, // Email address verified: bool, // Verification state verification_token: String, // UUID token } ``` ## Authentication Flow ### 1. Challenge-Response Authentication ```mermaid sequenceDiagram participant C as Client participant S as Server C->>S: POST /oauth/token (with signature) S->>S: Verify signature against public key S->>S: Generate JWT token S->>C: Return access_token C->>S: GET /oauth/userinfo (with Bearer token) S->>S: Validate JWT token S->>C: Return user profile ``` ### 2. JWT Token Validation 1. Extract Bearer token from Authorization header 2. Decode JWT using server secret 3. Validate issuer, audience, and expiration 4. Extract public key from subject claim 5. Look up user by public key 6. Return user information ## Error Handling ### Standard HTTP Status Codes - `200 OK`: Request successful - `400 Bad Request`: Invalid request format or data - `401 Unauthorized`: Authentication required or failed - `404 Not Found`: Resource not found - `500 Internal Server Error`: Server error ### OAuth 2.0 Error Format All OAuth errors follow RFC 6749 format: ```json { "error": "error_code", "error_description": "Human readable description", "error_uri": "https://docs.example.com/oauth/errors" } ``` ### Common Error Scenarios 1. **Email Not Verified** ```json { "success": false, "message": "Email not verified" } ``` 2. **Invalid Token** ```json { "error": "invalid_token", "error_description": "Invalid or expired token" } ``` 3. **User Not Found** ```json { "error": "invalid_client", "error_description": "User not found" } ``` ## Rate Limiting Currently not implemented but recommended for production: - **Email Verification**: 5 requests per email per hour - **Authentication**: 10 attempts per public key per minute - **Registration**: 3 registrations per IP per hour ## Security Headers The server should include security headers in production: ``` Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Content-Security-Policy: default-src 'self' ``` ## Monitoring and Logging ### Log Levels - **INFO**: Normal operations (requests, registrations) - **WARN**: Invalid tokens, failed verifications - **ERROR**: Server errors, database failures ### Metrics to Track - Request count by endpoint - Authentication success/failure rates - Registration completion rates - Email verification rates - Response times - Error rates ### Health Check Details The `/health` endpoint can be extended for detailed health information: ```json { "status": "healthy", "service": "self-server", "version": "1.0.0", "uptime": 3600, "checks": { "database": "healthy", "email_service": "healthy", "jwt_signing": "healthy" } } ``` ## Production Considerations ### Database Integration Replace in-memory storage with persistent database: ```rust // Example with SQLx async fn store_user(pool: &PgPool, user: &User) -> Result<(), sqlx::Error> { sqlx::query!( "INSERT INTO users (id, email, public_key, name, created_at) VALUES ($1, $2, $3, $4, $5)", user.id, user.email, user.public_key, user.name, user.created_at ) .execute(pool) .await?; Ok(()) } ``` ### SMTP Integration Replace console logging with actual email sending: ```rust use lettre::{SmtpTransport, Transport, Message}; async fn send_verification_email(email: &str, verification_url: &str) -> Result<(), Box> { let message = Message::builder() .from("noreply@yourapp.com".parse()?) .to(email.parse()?) .subject("Verify your email address") .body(format!("Click here to verify: {}", verification_url))?; let mailer = SmtpTransport::relay("smtp.gmail.com")? .credentials(Credentials::new("username".to_string(), "password".to_string())) .build(); mailer.send(&message)?; Ok(()) } ``` ### Environment Configuration ```rust #[derive(Parser, Debug)] struct Args { #[arg(short, long, default_value_t = 8080)] port: u16, #[arg(long, env = "DATABASE_URL")] database_url: String, #[arg(long, env = "JWT_SECRET")] jwt_secret: String, #[arg(long, env = "SMTP_HOST")] smtp_host: String, #[arg(long, env = "SMTP_USERNAME")] smtp_username: String, #[arg(long, env = "SMTP_PASSWORD")] smtp_password: String, } ```