{
  "openapi": "3.1.1",
  "info": {
    "title": "AnyOAuth management API",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://api.anyoauth.com"
    }
  ],
  "paths": {
    "/api/device": {
      "post": {
        "operationId": "startDeviceLogin",
        "x-tool-internal": true,
        "x-sdk-auth": "none",
        "description": "Start a ten-minute browser approval flow.",
        "responses": {
          "200": {
            "description": "Device login",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceLogin"
                }
              }
            }
          }
        }
      }
    },
    "/api/device/token": {
      "post": {
        "operationId": "pollDeviceLogin",
        "x-tool-internal": true,
        "x-sdk-auth": "none",
        "description": "Poll at most once every five seconds. Approved codes are consumed once.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "deviceCode"
                ],
                "properties": {
                  "deviceCode": {
                    "type": "string",
                    "pattern": "^aod_[A-Za-z0-9_-]{43}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pending or authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceResult"
                }
              }
            }
          }
        }
      }
    },
    "/api/me": {
      "get": {
        "operationId": "me",
        "x-sdk-auth": "management",
        "description": "Get the signed-in management account.",
        "responses": {
          "200": {
            "description": "Account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Owner"
                }
              }
            }
          }
        }
      }
    },
    "/api/logout": {
      "post": {
        "operationId": "logout",
        "x-tool-internal": true,
        "x-sdk-auth": "management",
        "description": "Revoke the current management token.",
        "responses": {
          "204": {
            "description": "Revoked"
          }
        }
      }
    },
    "/api/projects": {
      "get": {
        "operationId": "listProjects",
        "x-sdk-auth": "management",
        "description": "List your projects (newest first, up to 100).",
        "responses": {
          "200": {
            "description": "Projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProject",
        "x-sdk-auth": "management",
        "description": "Create a project. The client secret is returned only once; save it on the application's backend.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Project and one-time secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "project",
                    "clientSecret"
                  ],
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "clientSecret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{id}": {
      "put": {
        "operationId": "updateProject",
        "x-sdk-auth": "management",
        "description": "Replace a project's name, exact registered redirects, and enabled providers.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteProject",
        "x-sdk-auth": "management",
        "description": "Permanently delete a project and its identities and grants.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          }
        }
      }
    },
    "/api/projects/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateProjectSecret",
        "x-sdk-auth": "management",
        "description": "Rotate the client secret and retire outstanding grants/profile tokens. Returns the new secret once.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "New secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "clientSecret"
                  ],
                  "properties": {
                    "clientSecret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{id}/users": {
      "get": {
        "operationId": "listProjectUsers",
        "x-sdk-auth": "management",
        "description": "List up to 100 identities by most recent sign-in.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Identities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProjectUser"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{id}/users/{subject}": {
      "delete": {
        "operationId": "deleteProjectUser",
        "x-sdk-auth": "management",
        "description": "Delete a project's identity by subject.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "subject",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "LoginSessionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "client_id",
          "client_secret",
          "session_key",
          "provider",
          "redirect_uri"
        ],
        "properties": {
          "client_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "client_secret": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "session_key": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "provider": {
            "$ref": "#/components/schemas/Provider"
          },
          "redirect_uri": {
            "$ref": "#/components/schemas/RedirectUri"
          }
        }
      },
      "LoginSessionResponse": {
        "type": "object",
        "required": [
          "authorization_url",
          "expires_in"
        ],
        "properties": {
          "authorization_url": {
            "$ref": "#/components/schemas/RedirectUri"
          },
          "expires_in": {
            "type": "integer",
            "const": 600
          }
        }
      },
      "LoginResultRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "client_id",
          "client_secret",
          "session_key",
          "redirect_uri"
        ],
        "properties": {
          "client_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "client_secret": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "session_key": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "redirect_uri": {
            "$ref": "#/components/schemas/RedirectUri"
          }
        }
      },
      "LoginResult": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "succeeded",
              "failed"
            ]
          },
          "profile": {
            "$ref": "#/components/schemas/Profile"
          },
          "error": {
            "type": "string",
            "enum": [
              "access_denied",
              "invalid_provider_response",
              "provider_unavailable"
            ]
          }
        }
      },
      "Provider": {
        "type": "string",
        "enum": [
          "google",
          "github"
        ]
      },
      "RedirectUri": {
        "type": "string",
        "format": "uri",
        "maxLength": 2048,
        "x-validation": "redirect",
        "description": "Exact registered HTTPS URL or HTTP loopback; no credentials, query or fragment."
      },
      "TokenRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "grant_type",
          "client_id",
          "client_secret",
          "code",
          "redirect_uri",
          "code_verifier"
        ],
        "properties": {
          "grant_type": {
            "type": "string",
            "const": "authorization_code"
          },
          "client_id": {
            "type": "string",
            "maxLength": 100
          },
          "client_secret": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "redirect_uri": {
            "$ref": "#/components/schemas/RedirectUri"
          },
          "code_verifier": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._~-]{43,128}$"
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "scope"
        ],
        "properties": {
          "access_token": {
            "type": "string",
            "pattern": "^aop_[A-Za-z0-9_-]{43}$"
          },
          "token_type": {
            "type": "string",
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "const": 900
          },
          "scope": {
            "type": "string",
            "const": "profile"
          }
        }
      },
      "Profile": {
        "type": "object",
        "required": [
          "subject",
          "provider",
          "providerSubject",
          "name",
          "username",
          "email",
          "emailVerified",
          "avatarUrl"
        ],
        "properties": {
          "subject": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/Provider"
          },
          "providerSubject": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "emailVerified": {
            "type": "boolean"
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ProviderStatus": {
        "type": "object",
        "required": [
          "id",
          "configured",
          "enabled",
          "available"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Provider"
          },
          "configured": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean"
          },
          "available": {
            "type": "boolean"
          }
        }
      },
      "ProviderStatuses": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/ProviderStatus"
        }
      },
      "ApiError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Transaction": {
        "type": "object",
        "required": [
          "state",
          "codeVerifier",
          "codeChallenge",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "state": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "codeVerifier": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._~-]{43,128}$"
          },
          "codeChallenge": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "createdAt": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "integer"
          }
        }
      },
      "ProjectInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "redirectUris",
          "providers"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "pattern": "\\S"
          },
          "redirectUris": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/RedirectUri"
            }
          },
          "providers": {
            "type": "array",
            "minItems": 1,
            "maxItems": 2,
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/Provider"
            }
          }
        }
      },
      "Project": {
        "type": "object",
        "required": [
          "id",
          "name",
          "redirectUris",
          "providers",
          "createdAt",
          "userCount"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "redirectUris": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Provider"
            }
          },
          "createdAt": {
            "type": "integer"
          },
          "userCount": {
            "type": "integer"
          }
        }
      },
      "ProjectUser": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Profile"
          },
          {
            "type": "object",
            "required": [
              "createdAt",
              "lastSignInAt"
            ],
            "properties": {
              "createdAt": {
                "type": "integer"
              },
              "lastSignInAt": {
                "type": "integer"
              }
            }
          }
        ]
      },
      "Owner": {
        "type": "object",
        "required": [
          "id",
          "name",
          "email",
          "avatarUrl"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "DeviceLogin": {
        "type": "object",
        "required": [
          "deviceCode",
          "userCode",
          "verificationUri",
          "expiresIn",
          "interval"
        ],
        "properties": {
          "deviceCode": {
            "type": "string"
          },
          "userCode": {
            "type": "string",
            "pattern": "^[A-F0-9]{12}$"
          },
          "verificationUri": {
            "type": "string",
            "format": "uri"
          },
          "expiresIn": {
            "type": "integer",
            "const": 600
          },
          "interval": {
            "type": "integer",
            "const": 5
          }
        }
      },
      "DeviceResult": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "status"
            ],
            "properties": {
              "status": {
                "const": "pending"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "status",
              "token",
              "expiresAt"
            ],
            "properties": {
              "status": {
                "const": "authorized"
              },
              "token": {
                "type": "string",
                "pattern": "^aom_[A-Za-z0-9_-]{43}$"
              },
              "expiresAt": {
                "type": "integer"
              }
            }
          }
        ]
      }
    }
  }
}
