API System
The starter includes a comprehensive API system designed for secure, monitored programmatic access to your application. The system provides token-based authentication, IP allowlisting, request logging, and detailed analytics.
Default API Routes
Section titled “Default API Routes”The starter ships with a minimal set of API endpoints to support access token management and viewing user information. They live in routes/api.php and can be removed or extended as needed.
- GET
/api/health— Unauthenticated health check, exposed whenAPI_ENABLED=true - GET
/api/v1/me— Returns the authenticated API user profile - GET
/api/v1/me/tokens— Paginated list of the user’s access tokens - POST
/api/v1/me/tokens— Create a new access token - GET
/api/v1/me/tokens/{token}— Fetch a single access token - DELETE
/api/v1/me/tokens/{token}— Revoke an access token
View the API Specification for a complete reference of these endpoints. If your project does not need these defaults, delete or adjust the corresponding routes in routes/api.php.
Core Concepts
Section titled “Core Concepts”The API architecture is designed to separate human identity from machine identity, utilizing a strict one-to-many relationship between API Users and their Access Tokens.
API Users
Section titled “API Users”An API User represents a specific machine actor.
- Distinct from Humans - Separate from standard user accounts. They cannot log in through the UI.
- Scoped Authority - They can only be assigned API Integration roles to ensure they are never granted elevated permissions.
Access Tokens
Section titled “Access Tokens”Each API user can possess multiple Access Tokens. These are the actual credentials used in the Authorization header.
- Immediate Activation - Tokens are valid immediately upon creation.
- Optional Expiration - Tokens can be set to expire after a certain date, or remain valid indefinitely.
- Granular Restrictions - Each token can have its own specific IP allowlist, independent of other tokens belonging to the same user.
Strategy: Why Multiple Tokens?
Section titled “Strategy: Why Multiple Tokens?”In production environments, it is best practice to issue a unique token for every distinct service connecting to your API, even if they represent the same “API User” or organization.
- Isolation - A single compromised integration does not jeopardize others
- Safe Rotation - Rotate one token without interrupting other consumers
- Better Analytics - Usage logs are tied to the specific token. This allows you to see granular usage patterns per integration.
Key Features
Section titled “Key Features”Access Token Management
Section titled “Access Token Management”- Multi-Token Architecture - Create unique credentials for every consumer
- Flexible Lifecycles - Choose between ephemeral tokens with hard expiration dates or permanent keys for long-term usage
- Easy Revocation - Invalidate compromised credentials instantly through the administration panel
IP Allowlisting
Section titled “IP Allowlisting”- CIDR Notation Support - Restrict access to specific subnets (e.g.,
10.0.0.0/24) or single IPs - Multi-Origin Support - Allow a single token to be used from multiple distinct locations
Request Logging & Monitoring
Section titled “Request Logging & Monitoring”- Performance Metrics - Every request is timed and logged, allowing you to spot slow endpoints
- Traffic Analysis - Built-in charts visualize API usage, error rates, and endpoint popularity over time
- Sampling - Configurable logging rates to prevent database bloat in high-traffic environments
Authentication Flow
Section titled “Authentication Flow”-
Token Creation
An administrator creates an API user and generates a token through the administration panel. During creation, you may optionally set an Expiration. If omitted, the token remains valid indefinitely.
-
Token Delivery
The plain-text token is displayed once at creation. Be sure to copy and store it securely, as it cannot be retrieved later.
Bearer Token: abc123def456ghi789jkl012mno345pqr678stu901vwx234yz -
Client Request
The external client includes the token in the request header:
GET /api/users HTTP/1.1Host: your-app.northwestern.eduAuthorization: Bearer abc123def456ghi789jkl012mno345pqr678stu901vwx234yz -
System Validation
The middleware performs a sequence of checks:
- Format: Extracts the Bearer token
- Identity: Locates the API User by the token hash
- Validity: Checks if the token has been revoked or expired
- Security: Verifies the request IP matches the allowlist (if configured)
- Authorization: Grants access based on the API User’s assigned role(s)
-
Logging
After the response is sent, the system logs the request details for monitoring and analytics.
Expiration Notifications
Section titled “Expiration Notifications”To prevent service interruptions, the system automatically sends email notifications when a token is approaching its expiration date and the API User has an email address configured.
By default, notifications are sent 30, 14, 7, and 3 days before expiration, as well as on the final day.
You can adjust these intervals in the configuration:
'expiration_notifications' => [ 'enabled' => env('API_ACCESS_TOKEN_EXPIRATION_NOTIFICATIONS_ENABLED', true), 'intervals' => [30, 14, 7, 3, 1],],If you do not wish to send expiration notifications, you can disable this feature entirely:
API_ACCESS_TOKEN_EXPIRATION_NOTIFICATIONS_ENABLED=falseRequest Logging
Section titled “Request Logging”Requests to protected API endpoints are automatically logged to the api_request_logs table. This provides a lightweight mechanism for monitoring API usage and debugging issues.
What Gets Logged
Section titled “What Gets Logged”Every log entry includes:
| Field | Description |
|---|---|
trace_id | Unique request identifier |
user_id | ID of the authenticated user |
access_token_id | ID of the Access Token used for authentication (nullable) |
method | HTTP method (GET, POST, etc.) |
path | Request path (relative URL) |
route_name | Named route for the request (if applicable) |
ip_address | Source IP address |
status_code | HTTP status code |
duration_ms | Request duration in milliseconds |
response_bytes | Size of the response body in bytes (if measurable) |
user_agent | User agent string from the request (if provided) |
failure_reason | Authentication or request failure reason, if any |
created_at | Timestamp when the request was logged |
Sampling Configuration
Section titled “Sampling Configuration”To manage the database load, you can configure probabilistic sampling through environment variables:
API_REQUEST_LOGGING_SAMPLING_ENABLED=trueAPI_REQUEST_LOGGING_SAMPLING_RATE=0.1 // Log 10% of requestsProduction Considerations
Section titled “Production Considerations”This is a basic utility, not a replacement for full-scale observability solutions.
Database-based logging is immensely helpful during local development to spot slow endpoints, and monitor low-traffic non-production environments.
For production applications expecting high volume:
- Opt for a dedicated APM: Use legitimate tools like New Relic or Datadog for deeper insights and to avoid database bloat.
- Adjust sampling: If you keep this feature enabled in production, consider setting a very low sampling rate (or disabling it entirely) to avoid the database write overhead.
Authorization
Section titled “Authorization”To handle granular access control for API users, the system leverages the existing role and permission structure.
API Integration Role Type
Section titled “API Integration Role Type”API users can ONLY be assigned roles with a role type of API Integration. This is intentionally restrictive to prevent API users from being granted permissions that are not relevant or appropriate for programmatic access.
API-Relevant Permissions
Section titled “API-Relevant Permissions”When creating/editing API Integration roles, only permissions marked as API-relevant are presented for assignment. These are determined by the isApiRelevant() method on the PermissionEnum:
public function isApiRelevant(): bool{ return match ($this) { self::VIEW_USERS => true, default => false, };}As you add new permissions to the system, ensure to update this method accordingly.