openapi: 3.2.0 info: title: XRHealth Platform Auth API version: 1.0.0 description: Common API for XRHealth applications and approved integrations. servers: - url: /v1 tags: - name: Auth paths: /auth/passwordless/start: post: operationId: startPatientPasswordlessLogin summary: Send a one-time patient login code security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PasswordlessStartRequest' responses: '202': description: A code request was accepted. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/passwordless/verify: post: operationId: verifyPatientPasswordlessLogin summary: Exchange a one-time code for XRHealth tokens security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PasswordlessVerifyRequest' responses: '200': description: XRHealth access and refresh tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/public/passwordless/start: post: operationId: startPublicPatientPasswordlessLogin summary: Start passwordless login for a registered public client requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicPasswordlessStartRequest' responses: '202': description: A code request was accepted. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/public/passwordless/verify: post: operationId: verifyPublicPatientPasswordlessLogin summary: Exchange a passwordless code for a short-lived PKCE authorization code requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicPasswordlessVerifyRequest' responses: '200': description: A one-time authorization code. content: application/json: schema: $ref: '#/components/schemas/AuthorizationCodeResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/public/token: post: operationId: exchangePublicPatientToken summary: Exchange a PKCE authorization code or rotate a public-client refresh token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicTokenRequest' responses: '200': description: XRHealth access and refresh tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/public/token/revoke: post: operationId: revokePublicPatientToken summary: Revoke a public-client refresh token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicTokenRevokeRequest' responses: '200': description: The refresh token is no longer usable. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/token/refresh: post: operationId: refreshPatientToken summary: Rotate a patient refresh token security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshTokenRequest' responses: '200': description: Rotated XRHealth tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' tags: - Auth /auth/token/revoke: post: operationId: revokePatientToken summary: Revoke a patient refresh token security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshTokenRequest' responses: '200': description: The refresh token is no longer usable. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' tags: - Auth components: schemas: PublicPasswordlessVerifyRequest: type: object required: - client_id - request_id - email - code properties: client_id: type: string minLength: 8 maxLength: 128 request_id: type: string format: uuid email: type: string format: email code: type: string pattern: ^\d{4,8}$ additionalProperties: false AuthorizationCodeResponse: type: object required: - authorization_code - expires_in properties: authorization_code: type: string expires_in: type: integer example: 60 PublicTokenRevokeRequest: type: object required: - client_id - refresh_token properties: client_id: type: string minLength: 8 maxLength: 128 refresh_token: type: string minLength: 16 additionalProperties: false PublicTokenRequest: type: object required: - client_id - grant_type properties: client_id: type: string minLength: 8 maxLength: 128 grant_type: type: string enum: - authorization_code - refresh_token authorization_code: type: string minLength: 16 code_verifier: type: string minLength: 43 maxLength: 128 refresh_token: type: string minLength: 16 additionalProperties: false PasswordlessVerifyRequest: type: object required: - request_id - email - code properties: request_id: type: string format: uuid email: type: string format: email code: type: string pattern: ^\d{4,8}$ additionalProperties: false PasswordlessStartRequest: type: object required: - email properties: email: type: string format: email additionalProperties: false TokenResponse: type: object required: - token_type - access_token - expires_in - refresh_token - refresh_token_expires_in - subject - scope properties: token_type: type: string enum: - Bearer access_token: type: string expires_in: type: integer example: 900 refresh_token: type: string refresh_token_expires_in: type: integer example: 2592000 subject: type: string description: Opaque public patient subject. scope: type: string example: patient:login patient:read PublicPasswordlessStartRequest: type: object required: - client_id - email - code_challenge - code_challenge_method properties: client_id: type: string minLength: 8 maxLength: 128 email: type: string format: email code_challenge: type: string minLength: 43 maxLength: 128 code_challenge_method: type: string enum: - S256 additionalProperties: false RefreshTokenRequest: type: object required: - refresh_token properties: refresh_token: type: string minLength: 16 additionalProperties: false responses: RateLimited: description: The request was rate limited. BadRequest: description: The request is invalid. Unavailable: description: The authentication module is temporarily unavailable. Forbidden: description: The token does not have access to this resource. Unauthorized: description: The application or patient token is invalid. securitySchemes: applicationToken: type: apiKey in: header name: X-XRHealth-Application-Token patientBearer: type: http scheme: bearer bearerFormat: JWT