315 lines
11 KiB
YAML
315 lines
11 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Galaxy Auth / Session Service Public API
|
|
version: v1
|
|
description: |
|
|
This specification documents the implemented `galaxy/authsession` v1
|
|
public REST contract for the e-mail-code flow consumed by
|
|
`galaxy/gateway`.
|
|
|
|
Implemented public operations:
|
|
- `POST /api/v1/public/auth/send-email-code`
|
|
- `POST /api/v1/public/auth/confirm-email-code`
|
|
|
|
Contract rules:
|
|
- requests and responses are JSON only;
|
|
- request schemas reject unknown fields via `additionalProperties: false`;
|
|
- empty bodies, malformed JSON, multiple JSON objects, and unknown fields
|
|
are rejected as `400 invalid_request`;
|
|
- surrounding ASCII/Unicode whitespace is trimmed from input string fields
|
|
before validation;
|
|
- `send-email-code` remains success-shaped for existing, new, and blocked
|
|
e-mail addresses;
|
|
- `confirm-email-code` returns a ready `device_session_id` synchronously on
|
|
success.
|
|
tags:
|
|
- name: PublicAuth
|
|
description: Public unauthenticated e-mail-code authentication endpoints.
|
|
paths:
|
|
/api/v1/public/auth/send-email-code:
|
|
post:
|
|
tags:
|
|
- PublicAuth
|
|
operationId: sendEmailCode
|
|
summary: Start a public e-mail login challenge
|
|
description: |
|
|
Accepts one client e-mail address and starts the public challenge flow.
|
|
The outward result remains success-shaped even when the underlying
|
|
policy suppresses mail delivery for anti-enumeration purposes.
|
|
|
|
The JSON body stays unchanged. Gateway may additionally forward the
|
|
optional public `Accept-Language` header so auth can derive the
|
|
auth-mail locale and the create-only preferred-language candidate used
|
|
later during first-user creation. Missing or unsupported values fall
|
|
back to `en`.
|
|
security: []
|
|
parameters:
|
|
- $ref: "#/components/parameters/AcceptLanguage"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/SendEmailCodeRequest"
|
|
examples:
|
|
default:
|
|
value:
|
|
email: pilot@example.com
|
|
responses:
|
|
"200":
|
|
description: The login challenge was accepted.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/SendEmailCodeResponse"
|
|
examples:
|
|
accepted:
|
|
value:
|
|
challenge_id: challenge-123
|
|
"400":
|
|
$ref: "#/components/responses/SendEmailCodeBadRequestError"
|
|
"503":
|
|
$ref: "#/components/responses/ServiceUnavailableError"
|
|
/api/v1/public/auth/confirm-email-code:
|
|
post:
|
|
tags:
|
|
- PublicAuth
|
|
operationId: confirmEmailCode
|
|
summary: Confirm a public e-mail login challenge
|
|
description: |
|
|
Completes a previously issued `challenge_id`, validates the submitted
|
|
verification code, registers the standard base64-encoded raw 32-byte
|
|
Ed25519 `client_public_key`, validates the submitted IANA
|
|
`time_zone`, and returns the created `device_session_id`.
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ConfirmEmailCodeRequest"
|
|
examples:
|
|
default:
|
|
value:
|
|
challenge_id: challenge-123
|
|
code: "123456"
|
|
client_public_key: 11qYAYdk8v3K6Yw8QK6ZlQ2nP4Wm8Cq5g1H0K8vT9no=
|
|
time_zone: Europe/Kaliningrad
|
|
responses:
|
|
"200":
|
|
description: The device session was created and is ready for use.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ConfirmEmailCodeResponse"
|
|
examples:
|
|
accepted:
|
|
value:
|
|
device_session_id: device-session-123
|
|
"400":
|
|
$ref: "#/components/responses/ConfirmEmailCodeBadRequestError"
|
|
"403":
|
|
$ref: "#/components/responses/BlockedByPolicyError"
|
|
"404":
|
|
$ref: "#/components/responses/ChallengeNotFoundError"
|
|
"409":
|
|
$ref: "#/components/responses/SessionLimitExceededError"
|
|
"410":
|
|
$ref: "#/components/responses/ChallengeExpiredError"
|
|
"503":
|
|
$ref: "#/components/responses/ServiceUnavailableError"
|
|
components:
|
|
parameters:
|
|
AcceptLanguage:
|
|
name: Accept-Language
|
|
in: header
|
|
required: false
|
|
description: |
|
|
Optional RFC 9110 `Accept-Language` header forwarded by gateway so
|
|
auth can derive the auth-mail locale and create-only
|
|
preferred-language candidate. The first supported BCP 47 tag wins;
|
|
unsupported or missing values fall back to `en`.
|
|
schema:
|
|
type: string
|
|
schemas:
|
|
SendEmailCodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- email
|
|
properties:
|
|
email:
|
|
type: string
|
|
description: Single client e-mail address that should receive the login code.
|
|
format: email
|
|
SendEmailCodeResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- challenge_id
|
|
properties:
|
|
challenge_id:
|
|
type: string
|
|
description: Opaque challenge identifier returned by the Auth / Session Service.
|
|
ConfirmEmailCodeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- challenge_id
|
|
- code
|
|
- client_public_key
|
|
- time_zone
|
|
properties:
|
|
challenge_id:
|
|
type: string
|
|
description: Opaque challenge identifier previously returned by send-email-code.
|
|
code:
|
|
type: string
|
|
description: Verification code delivered to the client.
|
|
client_public_key:
|
|
type: string
|
|
description: Standard base64-encoded raw 32-byte Ed25519 public key registered for the new device session.
|
|
time_zone:
|
|
type: string
|
|
description: Client-selected IANA time zone name forwarded as create-only registration context.
|
|
ConfirmEmailCodeResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- device_session_id
|
|
properties:
|
|
device_session_id:
|
|
type: string
|
|
description: Stable identifier of the created device session.
|
|
ErrorResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- error
|
|
properties:
|
|
error:
|
|
$ref: "#/components/schemas/ErrorBody"
|
|
ErrorBody:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- code
|
|
- message
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: |
|
|
Stable gateway-generated or client-safe auth-adapter-projected
|
|
error code. Gateway-generated values include `invalid_request`,
|
|
`not_found`, `method_not_allowed`, `request_too_large`,
|
|
`rate_limited`, `internal_error`, and `service_unavailable`.
|
|
message:
|
|
type: string
|
|
description: Human-readable client-safe error description.
|
|
responses:
|
|
SendEmailCodeBadRequestError:
|
|
description: |
|
|
Request body or field values are invalid. This includes empty bodies,
|
|
malformed JSON, multiple JSON objects, unknown fields, and invalid
|
|
`email`.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
invalidRequest:
|
|
value:
|
|
error:
|
|
code: invalid_request
|
|
message: email must be a single valid email address
|
|
ConfirmEmailCodeBadRequestError:
|
|
description: |
|
|
Request body or field values are invalid. This includes malformed
|
|
request payloads, invalid confirmation codes, and malformed
|
|
`client_public_key` or `time_zone` values.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
invalidRequest:
|
|
value:
|
|
error:
|
|
code: invalid_request
|
|
message: challenge_id must not be empty
|
|
invalidCode:
|
|
value:
|
|
error:
|
|
code: invalid_code
|
|
message: confirmation code is invalid
|
|
invalidClientPublicKey:
|
|
value:
|
|
error:
|
|
code: invalid_client_public_key
|
|
message: client_public_key is not a valid base64-encoded raw 32-byte Ed25519 public key
|
|
invalidTimeZone:
|
|
value:
|
|
error:
|
|
code: invalid_request
|
|
message: time_zone must be a valid IANA time zone name
|
|
ChallengeNotFoundError:
|
|
description: The referenced challenge does not exist.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
notFound:
|
|
value:
|
|
error:
|
|
code: challenge_not_found
|
|
message: challenge not found
|
|
ChallengeExpiredError:
|
|
description: The referenced challenge has expired and can no longer be confirmed.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
expired:
|
|
value:
|
|
error:
|
|
code: challenge_expired
|
|
message: challenge expired
|
|
BlockedByPolicyError:
|
|
description: The auth flow is denied by account or registration policy.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
blocked:
|
|
value:
|
|
error:
|
|
code: blocked_by_policy
|
|
message: authentication is blocked by policy
|
|
SessionLimitExceededError:
|
|
description: Creating another active device session would exceed the configured limit.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
limitExceeded:
|
|
value:
|
|
error:
|
|
code: session_limit_exceeded
|
|
message: active session limit would be exceeded
|
|
ServiceUnavailableError:
|
|
description: The service is temporarily unable to serve the request safely.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
examples:
|
|
unavailable:
|
|
value:
|
|
error:
|
|
code: service_unavailable
|
|
message: service is unavailable
|