openapi: 3.2.0 info: title: OpenESPI Authorization Server OAuth2 Client Management API description: "OAuth2/OIDC Authorization Server for Green Button Alliance ESPI 4.0 compliant applications.\n\nThis API provides:\n- OAuth2 client management\n- DataCustodian integration\n- OIDC UserInfo endpoint with ESPI claims\n- NAESB ESPI 4.0 compliance features\n\n## Security\n\n- **TLS 1.3 ONLY**: All communications must use TLS 1.3\n- **Certificate Authentication**: Support for X.509 client certificates\n- **Bearer Token**: Required for API access\n- **Perfect Forward Secrecy**: All cipher suites support PFS\n\n## ESPI Compliance\n\nThis server is certified for NAESB ESPI 4.0 compliance and supports:\n- Green Button Connect My Data (CMD)\n- Function Block 4.5.15+ \n- Certificate-based client authentication\n- ESPI-specific scope validation\n" version: 1.0.0 contact: name: Green Button Alliance email: support@greenbuttonalliance.org url: https://www.greenbuttonalliance.org license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 termsOfService: https://www.greenbuttonalliance.org/terms servers: - url: https://authorization.greenbuttonalliance.org description: Production server - url: https://staging-authorization.greenbuttonalliance.org description: Staging server security: - BearerAuth: [] - ClientCertificate: [] tags: - name: OAuth2 Client Management description: Manage OAuth2 client registrations paths: /api/v1/oauth2/clients: get: tags: - OAuth2 Client Management summary: List OAuth2 clients description: Retrieve a paginated list of registered OAuth2 clients security: - BearerAuth: [] parameters: - name: page in: query description: Page number (zero-based) schema: type: integer default: 0 minimum: 0 - name: size in: query description: Page size schema: type: integer default: 20 minimum: 1 maximum: 100 - name: sort in: query description: Sort field schema: type: string enum: - clientName - clientId - createdAt default: clientName - name: direction in: query description: Sort direction schema: type: string enum: - ASC - DESC default: ASC - name: search in: query description: Search term for client name or ID schema: type: string - name: espiCompliant in: query description: Filter by ESPI compliance schema: type: boolean responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ClientListResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimit' post: tags: - OAuth2 Client Management summary: Create new OAuth2 client description: Register a new OAuth2 client security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateClientRequest' responses: '201': description: Client created successfully content: application/json: schema: $ref: '#/components/schemas/ClientResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/ValidationError' /api/v1/oauth2/clients/{clientId}: get: tags: - OAuth2 Client Management summary: Get client by ID description: Retrieve a specific OAuth2 client by ID security: - BearerAuth: [] parameters: - name: clientId in: path required: true description: Client identifier schema: type: string responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ClientResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' put: tags: - OAuth2 Client Management summary: Update client description: Update an existing OAuth2 client security: - BearerAuth: [] parameters: - name: clientId in: path required: true description: Client identifier schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateClientRequest' responses: '200': description: Client updated successfully content: application/json: schema: $ref: '#/components/schemas/ClientResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationError' delete: tags: - OAuth2 Client Management summary: Delete client description: Remove an OAuth2 client (soft delete) security: - BearerAuth: [] parameters: - name: clientId in: path required: true description: Client identifier schema: type: string responses: '200': description: Client deleted successfully content: application/json: schema: $ref: '#/components/schemas/DeleteResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /api/v1/oauth2/clients/{clientId}/metrics: get: tags: - OAuth2 Client Management summary: Get client metrics description: Retrieve usage metrics for a specific client security: - BearerAuth: [] parameters: - name: clientId in: path required: true description: Client identifier schema: type: string responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ClientMetricsResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' components: schemas: ClientSettings: type: object properties: requireAuthorizationConsent: type: boolean default: true requireProofKey: type: boolean default: true WeeklyStats: type: object properties: currentWeek: $ref: '#/components/schemas/WeekStats' previousWeek: $ref: '#/components/schemas/WeekStats' TokenSettings: type: object properties: accessTokenTimeToLive: type: string description: ISO 8601 duration (e.g., PT1H) default: PT1H refreshTokenTimeToLive: type: string description: ISO 8601 duration (e.g., P30D) default: P30D reuseRefreshTokens: type: boolean default: false ValidationErrorResponse: allOf: - $ref: '#/components/schemas/ErrorResponse' - type: object properties: details: type: array items: type: object properties: field: type: string message: type: string ClientSummary: type: object properties: clientId: type: string clientName: type: string espiCompliant: type: boolean securityLevel: type: string enum: - LOW - MEDIUM - HIGH certificationStatus: type: string enum: - PENDING - CERTIFIED - EXPIRED - REVOKED createdAt: type: string format: date-time lastUsed: type: string format: date-time UpdateClientRequest: type: object properties: clientName: type: string minLength: 1 maxLength: 100 redirectUris: type: array items: type: string format: uri scopes: type: array items: type: string authorizationGrantTypes: type: array items: type: string enum: - authorization_code - refresh_token - client_credentials clientAuthenticationMethods: type: array items: type: string enum: - client_secret_basic - client_secret_post - tls_client_auth espiCompliant: type: boolean securityLevel: type: string enum: - LOW - MEDIUM - HIGH clientSettings: $ref: '#/components/schemas/ClientSettings' tokenSettings: $ref: '#/components/schemas/TokenSettings' CreateClientRequest: type: object required: - clientName - redirectUris - scopes properties: clientName: type: string minLength: 1 maxLength: 100 redirectUris: type: array minItems: 1 items: type: string format: uri scopes: type: array minItems: 1 items: type: string authorizationGrantTypes: type: array items: type: string enum: - authorization_code - refresh_token - client_credentials default: - authorization_code - refresh_token clientAuthenticationMethods: type: array items: type: string enum: - client_secret_basic - client_secret_post - tls_client_auth default: - client_secret_basic espiCompliant: type: boolean default: false securityLevel: type: string enum: - LOW - MEDIUM - HIGH default: MEDIUM clientSettings: $ref: '#/components/schemas/ClientSettings' tokenSettings: $ref: '#/components/schemas/TokenSettings' ClientResponse: type: object properties: clientId: type: string clientName: type: string clientSecret: type: string description: '[PROTECTED] - Only returned on creation' redirectUris: type: array items: type: string format: uri scopes: type: array items: type: string authorizationGrantTypes: type: array items: type: string enum: - authorization_code - refresh_token - client_credentials clientAuthenticationMethods: type: array items: type: string enum: - client_secret_basic - client_secret_post - tls_client_auth espiCompliant: type: boolean securityLevel: type: string enum: - LOW - MEDIUM - HIGH certificationStatus: type: string enum: - PENDING - CERTIFIED - EXPIRED - REVOKED createdAt: type: string format: date-time updatedAt: type: string format: date-time lastUsed: type: string format: date-time usageMetrics: $ref: '#/components/schemas/UsageMetrics' Pageable: type: object properties: sort: type: object properties: sorted: type: boolean orderBy: type: string pageNumber: type: integer pageSize: type: integer ClientMetricsResponse: type: object properties: clientId: type: string metrics: $ref: '#/components/schemas/UsageMetrics' WeekStats: type: object properties: authorizationsGranted: type: integer tokensIssued: type: integer ErrorResponse: type: object properties: error: type: string error_description: type: string error_uri: type: string format: uri timestamp: type: string format: date-time path: type: string correlationId: type: string ClientListResponse: type: object properties: content: type: array items: $ref: '#/components/schemas/ClientSummary' pageable: $ref: '#/components/schemas/Pageable' totalElements: type: integer format: int64 totalPages: type: integer first: type: boolean last: type: boolean UsageMetrics: type: object properties: totalTokensIssued: type: integer format: int64 totalAuthorizationsGranted: type: integer format: int64 totalRefreshTokensUsed: type: integer format: int64 averageTokenLifetime: type: integer description: Average token lifetime in seconds lastTokenIssuedAt: type: string format: date-time peakUsageHour: type: integer minimum: 0 maximum: 23 weeklyStats: $ref: '#/components/schemas/WeeklyStats' DeleteResponse: type: object properties: message: type: string clientId: type: string deletedAt: type: string format: date-time responses: NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: client_not_found error_description: The specified client was not found timestamp: '2024-01-16T15:30:00Z' Unauthorized: description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: invalid_token error_description: The access token is invalid or expired timestamp: '2024-01-16T15:30:00Z' Conflict: description: Conflict content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: client_already_exists error_description: A client with this ID already exists timestamp: '2024-01-16T15:30:00Z' RateLimit: description: Rate limit exceeded headers: X-RateLimit-Limit: schema: type: integer description: Request limit per hour X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Unix timestamp when limit resets content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: rate_limit_exceeded error_description: Too many requests timestamp: '2024-01-16T15:30:00Z' ValidationError: description: Validation error content: application/json: schema: $ref: '#/components/schemas/ValidationErrorResponse' example: error: validation_error error_description: Request validation failed timestamp: '2024-01-16T15:30:00Z' details: - field: clientName message: Client name is required Forbidden: description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: insufficient_scope error_description: The request requires higher privileges timestamp: '2024-01-16T15:30:00Z' BadRequest: description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: invalid_request error_description: The request is malformed timestamp: '2024-01-16T15:30:00Z' path: /api/v1/oauth2/clients securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT ClientCredentials: type: http scheme: basic ClientCertificate: type: mutualTLS externalDocs: description: OpenESPI Authorization Server Documentation url: https://docs.greenbuttonalliance.org/authorization-server