# API Reference: OIDC Groups This document describes the API changes related to OIDC group storage and management introduced in Headscale v0.24.0. ## Overview Headscale now stores OIDC group membership information extracted from authentication claims. This enables external integrations to implement role-based access control based on a user's group membership. ## User API Changes ### User Object Schema The User object now includes group information when users authenticate via OIDC: ```json { "id": "1", "name": "alice", "createdAt": "2024-01-01T00:00:00Z", "displayName": "Alice Smith", "email": "alice@example.com", "providerId": "https://provider.com/alice", "provider": "oidc", "profilePicUrl": "https://provider.com/avatar/alice.jpg", "groups": ["admin", "developers", "security-team"] } ``` ### Field Descriptions | Field | Type | Description | |-------|------|-------------| | `groups` | `string[]` | Array of group names extracted from OIDC claims. Empty array for non-OIDC users. | ## API Endpoints ### List Users Returns all users including their group membership. **Request:** ```http GET /api/v1/user Authorization: Bearer ``` **Response:** ```json { "users": [ { "id": "1", "name": "alice", "email": "alice@example.com", "provider": "oidc", "groups": ["admin", "developers"] }, { "id": "2", "name": "bob", "email": "", "provider": "cli", "groups": [] } ] } ``` ### Get User Returns a specific user including group membership. **Request:** ```http GET /api/v1/user/{name} Authorization: Bearer ``` **Response:** ```json { "user": { "id": "1", "name": "alice", "email": "alice@example.com", "provider": "oidc", "groups": ["admin", "developers", "security-team"] } } ``` ## Group Management ### Automatic Group Updates Groups are automatically updated when OIDC users authenticate: 1. User logs in via OIDC 2. Groups are extracted from ID token and/or UserInfo endpoint 3. User's group membership is updated in the database 4. API responses include updated group information ### Group Sources Groups can be extracted from multiple sources in OIDC claims: - **Standard `groups` claim**: Most common format - **`roles` claim**: Alternative role-based claim - **Provider-specific claims**: e.g., `cognito:groups` for AWS Cognito - **Nested claims**: e.g., `resource_access.client.roles` for Keycloak ### Group Validation - Only string values are accepted as group names - Empty or null groups are filtered out - Group names are stored as-is (case-sensitive) - Maximum reasonable limit of groups per user (no strict limit enforced) ## Integration Examples ### Role-Based Access Control External applications can query user groups for access control: ```bash # Get user groups via API curl -H "Authorization: Bearer $API_KEY" \ https://headscale.example.com/api/v1/user/alice | \ jq '.user.groups[]' # Check if user has admin group curl -H "Authorization: Bearer $API_KEY" \ https://headscale.example.com/api/v1/user/alice | \ jq '.user.groups | contains(["admin"])' ``` ### Database Queries For direct database access: ```sql -- Get all users with their groups SELECT name, email, groups FROM users WHERE provider = 'oidc'; -- Find users in specific group SELECT name FROM users WHERE provider = 'oidc' AND JSON_EXTRACT(groups, '$') LIKE '%"admin"%'; -- Count users by group membership SELECT json_each.value as group_name, COUNT(*) as user_count FROM users, json_each(users.groups) WHERE provider = 'oidc' GROUP BY json_each.value; ``` ## WebUI Integration ### Headplane Integration When using Headplane as a web interface, the groups information enables: - **Automatic Role Assignment**: Map OIDC groups to Headplane roles - **Dynamic Permissions**: Update user capabilities based on current group membership - **Audit Trails**: Track role assignments based on group changes Example Headplane API usage: ```javascript // Fetch user with groups const response = await fetch('/api/v1/user/alice', { headers: { 'Authorization': `Bearer ${apiKey}` } }); const user = await response.json(); // Map groups to roles const roles = mapGroupsToRoles(user.groups); console.log(`User ${user.name} has roles:`, roles); ``` ## Backward Compatibility ### CLI Users - Users created via CLI (`headscale users create`) have empty groups array - No changes to existing CLI user management - Groups field is optional and defaults to empty array ### API Compatibility - All existing API endpoints continue to work unchanged - New `groups` field is additive (doesn't break existing clients) - Clients can safely ignore the groups field if not needed ### Migration - Existing OIDC users will have empty groups until next login - No database migration required for basic functionality - Groups are populated automatically on subsequent OIDC logins ## Configuration ### Headscale Configuration Ensure groups scope is included for group extraction: ```yaml oidc: issuer: "https://your-provider.com" client_id: "headscale" client_secret: "your-secret" scope: ["openid", "profile", "email", "groups"] ``` ### Provider-Specific Configuration === "Keycloak" ```yaml # Keycloak automatically includes groups in standard format oidc: scope: ["openid", "profile", "email", "groups"] ``` === "Azure AD" ```yaml # Azure AD requires group claims configuration oidc: scope: ["openid", "profile", "email"] # Groups included via claims configuration in Azure AD ``` === "Okta" ```yaml # Okta supports groups in tokens oidc: scope: ["openid", "profile", "email", "groups"] ``` ## Error Handling ### Common Issues **Groups not appearing:** - Verify `groups` scope is included in OIDC configuration - Check identity provider group claim configuration - Ensure user is member of groups in identity provider **Invalid group data:** - Non-string group values are automatically filtered out - Empty arrays are valid (user has no groups) - Malformed JSON is handled gracefully with empty array fallback ### Error Responses Standard HTTP error codes apply: - `401 Unauthorized`: Invalid or missing API key - `404 Not Found`: User does not exist - `500 Internal Server Error`: Server-side processing error ## Security Considerations ### Access Control - Groups information is available to any client with valid API key - Consider creating read-only API keys for external integrations - Audit API key usage for compliance requirements ### Data Privacy - Group names may contain sensitive organizational information - Consider data classification for group membership information - Implement appropriate access controls for group data ### Token Security - Groups are extracted from verified OIDC tokens only - Token validation ensures groups cannot be spoofed - Groups are updated only during successful authentication ## Monitoring and Observability ### Metrics Monitor group extraction and updates: - Number of OIDC logins with groups extracted - Distribution of group membership across users - Failed group extractions or parsing errors ### Logging Key log events to monitor: - Group extraction from OIDC claims - Group updates during user authentication - Group parsing errors or validation failures Example log entries: ``` INFO Groups extracted from OIDC claims user=alice groups=["admin","developers"] WARN Invalid group value filtered out user=bob value=123 type=number ERROR Failed to parse groups from OIDC claims user=charlie error="invalid JSON" ``` This API enhancement provides the foundation for implementing sophisticated role-based access control systems while maintaining backward compatibility with existing deployments.