{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "RootConfig",
  "description": "Application configuration root",
  "type": "object",
  "properties": {
    "clients": {
      "description": "List of OAuth 2.0/OIDC clients config",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ClientConfig"
      }
    },
    "http": {
      "description": "Configuration of the HTTP server",
      "default": {
        "listeners": [
          {
            "name": "web",
            "resources": [
              {
                "name": "discovery"
              },
              {
                "name": "human"
              },
              {
                "name": "oauth"
              },
              {
                "name": "compat"
              },
              {
                "name": "graphql"
              },
              {
                "name": "assets"
              }
            ],
            "binds": [
              {
                "address": "[::]:8080"
              }
            ],
            "proxy_protocol": false
          },
          {
            "name": "internal",
            "resources": [
              {
                "name": "health"
              }
            ],
            "binds": [
              {
                "host": "localhost",
                "port": 8081
              }
            ],
            "proxy_protocol": false
          }
        ],
        "trusted_proxies": [
          "192.168.0.0/16",
          "172.16.0.0/12",
          "10.0.0.0/10",
          "127.0.0.1/8",
          "fd00::/8",
          "::1/128"
        ],
        "public_base": "http://[::]:8080/",
        "issuer": "http://[::]:8080/"
      },
      "allOf": [
        {
          "$ref": "#/definitions/HttpConfig"
        }
      ]
    },
    "database": {
      "description": "Database connection configuration",
      "default": {
        "uri": "postgresql://",
        "max_connections": 10,
        "min_connections": 0,
        "connect_timeout": 30,
        "idle_timeout": 600,
        "max_lifetime": 1800
      },
      "allOf": [
        {
          "$ref": "#/definitions/DatabaseConfig"
        }
      ]
    },
    "telemetry": {
      "description": "Configuration related to sending monitoring data",
      "allOf": [
        {
          "$ref": "#/definitions/TelemetryConfig"
        }
      ]
    },
    "templates": {
      "description": "Configuration related to templates",
      "allOf": [
        {
          "$ref": "#/definitions/TemplatesConfig"
        }
      ]
    },
    "email": {
      "description": "Configuration related to sending emails",
      "default": {
        "from": "\"Authentication Service\" <root@localhost>",
        "reply_to": "\"Authentication Service\" <root@localhost>",
        "transport": "blackhole"
      },
      "allOf": [
        {
          "$ref": "#/definitions/EmailConfig"
        }
      ]
    },
    "secrets": {
      "description": "Application secrets",
      "allOf": [
        {
          "$ref": "#/definitions/SecretsConfig"
        }
      ]
    },
    "passwords": {
      "description": "Configuration related to user passwords",
      "default": {
        "enabled": true,
        "schemes": [
          {
            "version": 1,
            "algorithm": "argon2id"
          }
        ],
        "minimum_complexity": 3
      },
      "allOf": [
        {
          "$ref": "#/definitions/PasswordsConfig"
        }
      ]
    },
    "matrix": {
      "description": "Configuration related to the homeserver",
      "allOf": [
        {
          "$ref": "#/definitions/MatrixConfig"
        }
      ]
    },
    "policy": {
      "description": "Configuration related to the OPA policies",
      "allOf": [
        {
          "$ref": "#/definitions/PolicyConfig"
        }
      ]
    },
    "rate_limiting": {
      "description": "Configuration related to limiting the rate of user actions to prevent\n abuse",
      "allOf": [
        {
          "$ref": "#/definitions/RateLimitingConfig"
        }
      ]
    },
    "upstream_oauth2": {
      "description": "Configuration related to upstream OAuth providers",
      "allOf": [
        {
          "$ref": "#/definitions/UpstreamOAuth2Config"
        }
      ]
    },
    "branding": {
      "description": "Configuration section for tweaking the branding of the service",
      "allOf": [
        {
          "$ref": "#/definitions/BrandingConfig"
        }
      ]
    },
    "captcha": {
      "description": "Configuration section to setup CAPTCHA protection on a few operations",
      "allOf": [
        {
          "$ref": "#/definitions/CaptchaConfig"
        }
      ]
    },
    "account": {
      "description": "Configuration section to configure features related to account\n management",
      "allOf": [
        {
          "$ref": "#/definitions/AccountConfig"
        }
      ]
    },
    "experimental": {
      "description": "Experimental configuration options",
      "allOf": [
        {
          "$ref": "#/definitions/ExperimentalConfig"
        }
      ]
    }
  },
  "required": [
    "secrets",
    "matrix"
  ],
  "definitions": {
    "ClientConfig": {
      "description": "An OAuth 2.0 client configuration",
      "type": "object",
      "properties": {
        "client_id": {
          "description": "A ULID as per https://github.com/ulid/spec",
          "type": "string",
          "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
        },
        "client_auth_method": {
          "description": "Authentication method used for this client",
          "allOf": [
            {
              "$ref": "#/definitions/ClientAuthMethodConfig"
            }
          ]
        },
        "client_name": {
          "description": "Name of the `OAuth2` client",
          "type": [
            "string",
            "null"
          ]
        },
        "client_secret_file": {
          "description": "Path to the file containing the client secret. The client secret is used\n by the `client_secret_basic`, `client_secret_post` and\n `client_secret_jwt` authentication methods.",
          "type": [
            "string",
            "null"
          ]
        },
        "client_secret": {
          "description": "Alternative to `client_secret_file`: Reads the client secret directly\n from the config.",
          "type": [
            "string",
            "null"
          ]
        },
        "jwks": {
          "description": "The JSON Web Key Set (JWKS) used by the `private_key_jwt` authentication\n method. Mutually exclusive with `jwks_uri`",
          "anyOf": [
            {
              "$ref": "#/definitions/JsonWebKeySet_for_JsonWebKeyPublicParameters"
            },
            {
              "type": "null"
            }
          ]
        },
        "jwks_uri": {
          "description": "The URL of the JSON Web Key Set (JWKS) used by the `private_key_jwt`\n authentication method. Mutually exclusive with `jwks`",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "redirect_uris": {
          "description": "List of allowed redirect URIs",
          "type": "array",
          "items": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "required": [
        "client_id",
        "client_auth_method"
      ]
    },
    "ClientAuthMethodConfig": {
      "description": "Authentication method used by clients",
      "oneOf": [
        {
          "description": "`none`: No authentication",
          "type": "string",
          "const": "none"
        },
        {
          "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic\n authorization credentials",
          "type": "string",
          "const": "client_secret_basic"
        },
        {
          "description": "`client_secret_post`: `client_id` and `client_secret` sent in the\n request body",
          "type": "string",
          "const": "client_secret_post"
        },
        {
          "description": "`client_secret_basic`: a `client_assertion` sent in the request body and\n signed using the `client_secret`",
          "type": "string",
          "const": "client_secret_jwt"
        },
        {
          "description": "`client_secret_basic`: a `client_assertion` sent in the request body and\n signed by an asymmetric key",
          "type": "string",
          "const": "private_key_jwt"
        }
      ]
    },
    "JsonWebKeySet_for_JsonWebKeyPublicParameters": {
      "type": "object",
      "properties": {
        "keys": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/JsonWebKey_for_JsonWebKeyPublicParameters"
          }
        }
      },
      "required": [
        "keys"
      ]
    },
    "JsonWebKey_for_JsonWebKeyPublicParameters": {
      "type": "object",
      "properties": {
        "use": {
          "anyOf": [
            {
              "$ref": "#/definitions/JsonWebKeyUse"
            },
            {
              "type": "null"
            }
          ]
        },
        "key_ops": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "$ref": "#/definitions/JsonWebKeyOperation"
          }
        },
        "alg": {
          "anyOf": [
            {
              "$ref": "#/definitions/JsonWebSignatureAlg"
            },
            {
              "type": "null"
            }
          ]
        },
        "kid": {
          "type": [
            "string",
            "null"
          ]
        },
        "x5u": {
          "type": [
            "string",
            "null"
          ]
        },
        "x5c": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "x5t": {
          "type": [
            "string",
            "null"
          ]
        },
        "x5t#S256": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kty": {
              "type": "string",
              "const": "RSA"
            }
          },
          "required": [
            "kty"
          ],
          "allOf": [
            {
              "$ref": "#/definitions/RsaPublicParameters"
            }
          ]
        },
        {
          "type": "object",
          "properties": {
            "kty": {
              "type": "string",
              "const": "EC"
            }
          },
          "required": [
            "kty"
          ],
          "allOf": [
            {
              "$ref": "#/definitions/EcPublicParameters"
            }
          ]
        },
        {
          "type": "object",
          "properties": {
            "kty": {
              "type": "string",
              "const": "OKP"
            }
          },
          "required": [
            "kty"
          ],
          "allOf": [
            {
              "$ref": "#/definitions/OkpPublicParameters"
            }
          ]
        }
      ]
    },
    "RsaPublicParameters": {
      "type": "object",
      "properties": {
        "n": {
          "type": "string"
        },
        "e": {
          "type": "string"
        }
      },
      "required": [
        "n",
        "e"
      ]
    },
    "JsonWebKeyEcEllipticCurve": {
      "description": "JSON Web Key EC Elliptic Curve",
      "anyOf": [
        {
          "description": "P-256 Curve",
          "const": "P-256"
        },
        {
          "description": "P-384 Curve",
          "const": "P-384"
        },
        {
          "description": "P-521 Curve",
          "const": "P-521"
        },
        {
          "description": "SECG secp256k1 curve",
          "const": "secp256k1"
        }
      ]
    },
    "EcPublicParameters": {
      "type": "object",
      "properties": {
        "crv": {
          "$ref": "#/definitions/JsonWebKeyEcEllipticCurve"
        },
        "x": {
          "type": "string"
        },
        "y": {
          "type": "string"
        }
      },
      "required": [
        "crv",
        "x",
        "y"
      ]
    },
    "JsonWebKeyOkpEllipticCurve": {
      "description": "JSON Web Key OKP Elliptic Curve",
      "anyOf": [
        {
          "description": "Ed25519 signature algorithm key pairs",
          "const": "Ed25519"
        },
        {
          "description": "Ed448 signature algorithm key pairs",
          "const": "Ed448"
        },
        {
          "description": "X25519 function key pairs",
          "const": "X25519"
        },
        {
          "description": "X448 function key pairs",
          "const": "X448"
        }
      ]
    },
    "OkpPublicParameters": {
      "type": "object",
      "properties": {
        "crv": {
          "$ref": "#/definitions/JsonWebKeyOkpEllipticCurve"
        },
        "x": {
          "type": "string"
        }
      },
      "required": [
        "crv",
        "x"
      ]
    },
    "JsonWebKeyUse": {
      "description": "JSON Web Key Use",
      "anyOf": [
        {
          "description": "Digital Signature or MAC",
          "const": "sig"
        },
        {
          "description": "Encryption",
          "const": "enc"
        }
      ]
    },
    "JsonWebKeyOperation": {
      "description": "JSON Web Key Operation",
      "anyOf": [
        {
          "description": "Compute digital signature or MAC",
          "const": "sign"
        },
        {
          "description": "Verify digital signature or MAC",
          "const": "verify"
        },
        {
          "description": "Encrypt content",
          "const": "encrypt"
        },
        {
          "description": "Decrypt content and validate decryption, if applicable",
          "const": "decrypt"
        },
        {
          "description": "Encrypt key",
          "const": "wrapKey"
        },
        {
          "description": "Decrypt key and validate decryption, if applicable",
          "const": "unwrapKey"
        },
        {
          "description": "Derive key",
          "const": "deriveKey"
        },
        {
          "description": "Derive bits not to be used as a key",
          "const": "deriveBits"
        }
      ]
    },
    "JsonWebSignatureAlg": {
      "description": "JSON Web Signature \"alg\" parameter",
      "anyOf": [
        {
          "description": "HMAC using SHA-256",
          "const": "HS256"
        },
        {
          "description": "HMAC using SHA-384",
          "const": "HS384"
        },
        {
          "description": "HMAC using SHA-512",
          "const": "HS512"
        },
        {
          "description": "RSASSA-PKCS1-v1_5 using SHA-256",
          "const": "RS256"
        },
        {
          "description": "RSASSA-PKCS1-v1_5 using SHA-384",
          "const": "RS384"
        },
        {
          "description": "RSASSA-PKCS1-v1_5 using SHA-512",
          "const": "RS512"
        },
        {
          "description": "ECDSA using P-256 and SHA-256",
          "const": "ES256"
        },
        {
          "description": "ECDSA using P-384 and SHA-384",
          "const": "ES384"
        },
        {
          "description": "ECDSA using P-521 and SHA-512",
          "const": "ES512"
        },
        {
          "description": "RSASSA-PSS using SHA-256 and MGF1 with SHA-256",
          "const": "PS256"
        },
        {
          "description": "RSASSA-PSS using SHA-384 and MGF1 with SHA-384",
          "const": "PS384"
        },
        {
          "description": "RSASSA-PSS using SHA-512 and MGF1 with SHA-512",
          "const": "PS512"
        },
        {
          "description": "No digital signature or MAC performed",
          "const": "none"
        },
        {
          "description": "EdDSA signature algorithms",
          "const": "EdDSA"
        },
        {
          "description": "ECDSA using secp256k1 curve and SHA-256",
          "const": "ES256K"
        },
        {
          "description": "EdDSA using Ed25519 curve",
          "const": "Ed25519"
        },
        {
          "description": "EdDSA using Ed448 curve",
          "const": "Ed448"
        }
      ]
    },
    "HttpConfig": {
      "description": "Configuration related to the web server",
      "type": "object",
      "properties": {
        "listeners": {
          "description": "List of listeners to run",
          "type": "array",
          "items": {
            "$ref": "#/definitions/ListenerConfig"
          },
          "default": []
        },
        "trusted_proxies": {
          "description": "List of trusted reverse proxies that can set the `X-Forwarded-For`\n header",
          "type": "array",
          "items": {
            "type": "string",
            "format": "ip"
          },
          "default": [
            "192.168.0.0/16",
            "172.16.0.0/12",
            "10.0.0.0/10",
            "127.0.0.1/8",
            "fd00::/8",
            "::1/128"
          ]
        },
        "public_base": {
          "description": "Public URL base from where the authentication service is reachable",
          "type": "string",
          "format": "uri"
        },
        "issuer": {
          "description": "OIDC issuer URL. Defaults to `public_base` if not set.",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        }
      },
      "required": [
        "public_base"
      ]
    },
    "ListenerConfig": {
      "description": "Configuration of a listener",
      "type": "object",
      "properties": {
        "name": {
          "description": "A unique name for this listener which will be shown in traces and in\n metrics labels",
          "type": [
            "string",
            "null"
          ]
        },
        "resources": {
          "description": "List of resources to mount",
          "type": "array",
          "items": {
            "$ref": "#/definitions/Resource"
          }
        },
        "prefix": {
          "description": "HTTP prefix to mount the resources on",
          "type": [
            "string",
            "null"
          ]
        },
        "binds": {
          "description": "List of sockets to bind",
          "type": "array",
          "items": {
            "$ref": "#/definitions/BindConfig"
          }
        },
        "proxy_protocol": {
          "description": "Accept `HAProxy`'s Proxy Protocol V1",
          "type": "boolean",
          "default": false
        },
        "tls": {
          "description": "If set, makes the listener use TLS with the provided certificate and key",
          "anyOf": [
            {
              "$ref": "#/definitions/TlsConfig"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "required": [
        "resources",
        "binds"
      ]
    },
    "Resource": {
      "description": "HTTP resources to mount",
      "oneOf": [
        {
          "description": "Healthcheck endpoint (/health)",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "health"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Prometheus metrics endpoint (/metrics)",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "prometheus"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "OIDC discovery endpoints",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "discovery"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Pages destined to be viewed by humans",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "human"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "GraphQL endpoint",
          "type": "object",
          "properties": {
            "playground": {
              "description": "Enabled the GraphQL playground",
              "type": "boolean"
            },
            "undocumented_oauth2_access": {
              "description": "Allow access for OAuth 2.0 clients (undocumented)",
              "type": "boolean"
            },
            "name": {
              "type": "string",
              "const": "graphql"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "OAuth-related APIs",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "oauth"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Matrix compatibility API",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "compat"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Static files",
          "type": "object",
          "properties": {
            "path": {
              "description": "Path to the directory to serve.",
              "type": "string"
            },
            "name": {
              "type": "string",
              "const": "assets"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Admin API, served at `/api/admin/v1`",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "adminapi"
            }
          },
          "required": [
            "name"
          ]
        },
        {
          "description": "Mount a \"/connection-info\" handler which helps debugging informations on\n the upstream connection",
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "const": "connection-info"
            }
          },
          "required": [
            "name"
          ]
        }
      ]
    },
    "BindConfig": {
      "description": "Configuration of a single listener",
      "anyOf": [
        {
          "description": "Listen on the specified host and port",
          "type": "object",
          "properties": {
            "host": {
              "description": "Host on which to listen.\n\n Defaults to listening on all addresses",
              "type": [
                "string",
                "null"
              ]
            },
            "port": {
              "description": "Port on which to listen.",
              "type": "integer",
              "format": "uint16",
              "minimum": 0,
              "maximum": 65535
            }
          },
          "required": [
            "port"
          ]
        },
        {
          "description": "Listen on the specified address",
          "type": "object",
          "properties": {
            "address": {
              "description": "Host and port on which to listen",
              "type": "string",
              "examples": [
                "[::1]:8080",
                "[::]:8080",
                "127.0.0.1:8080",
                "0.0.0.0:8080"
              ]
            }
          },
          "required": [
            "address"
          ]
        },
        {
          "description": "Listen on a UNIX domain socket",
          "type": "object",
          "properties": {
            "socket": {
              "description": "Path to the socket",
              "type": "string"
            }
          },
          "required": [
            "socket"
          ]
        },
        {
          "description": "Accept connections on file descriptors passed by the parent process.\n\n This is useful for grabbing sockets passed by systemd.\n\n See <https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html>",
          "type": "object",
          "properties": {
            "fd": {
              "description": "Index of the file descriptor. Note that this is offseted by 3\n because of the standard input/output sockets, so setting\n here a value of `0` will grab the file descriptor `3`",
              "type": "integer",
              "format": "uint",
              "minimum": 0,
              "default": 0
            },
            "kind": {
              "description": "Whether the socket is a TCP socket or a UNIX domain socket. Defaults\n to TCP.",
              "default": "tcp",
              "allOf": [
                {
                  "$ref": "#/definitions/UnixOrTcp"
                }
              ]
            }
          }
        }
      ]
    },
    "UnixOrTcp": {
      "description": "Kind of socket",
      "oneOf": [
        {
          "description": "UNIX domain socket",
          "type": "string",
          "const": "unix"
        },
        {
          "description": "TCP socket",
          "type": "string",
          "const": "tcp"
        }
      ]
    },
    "TlsConfig": {
      "description": "Configuration related to TLS on a listener",
      "type": "object",
      "properties": {
        "certificate": {
          "description": "PEM-encoded X509 certificate chain\n\n Exactly one of `certificate` or `certificate_file` must be set.",
          "type": [
            "string",
            "null"
          ]
        },
        "certificate_file": {
          "description": "File containing the PEM-encoded X509 certificate chain\n\n Exactly one of `certificate` or `certificate_file` must be set.",
          "type": [
            "string",
            "null"
          ]
        },
        "key": {
          "description": "PEM-encoded private key\n\n Exactly one of `key` or `key_file` must be set.",
          "type": [
            "string",
            "null"
          ]
        },
        "key_file": {
          "description": "File containing a PEM or DER-encoded private key\n\n Exactly one of `key` or `key_file` must be set.",
          "type": [
            "string",
            "null"
          ]
        },
        "password": {
          "description": "Password used to decode the private key\n\n One of `password` or `password_file` must be set if the key is\n encrypted.",
          "type": [
            "string",
            "null"
          ]
        },
        "password_file": {
          "description": "Password file used to decode the private key\n\n One of `password` or `password_file` must be set if the key is\n encrypted.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "DatabaseConfig": {
      "description": "Database connection configuration",
      "type": "object",
      "properties": {
        "uri": {
          "description": "Connection URI\n\n This must not be specified if `host`, `port`, `socket`, `username`,\n `password`, or `database` are specified.",
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "default": "postgresql://"
        },
        "host": {
          "description": "Name of host to connect to\n\n This must not be specified if `uri` is specified.",
          "anyOf": [
            {
              "$ref": "#/definitions/Hostname"
            },
            {
              "type": "null"
            }
          ]
        },
        "port": {
          "description": "Port number to connect at the server host\n\n This must not be specified if `uri` is specified.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint16",
          "minimum": 1,
          "maximum": 65535
        },
        "socket": {
          "description": "Directory containing the UNIX socket to connect to\n\n This must not be specified if `uri` is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "username": {
          "description": "PostgreSQL user name to connect as\n\n This must not be specified if `uri` is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "password": {
          "description": "Password to be used if the server demands password authentication\n\n This must not be specified if `uri` is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "database": {
          "description": "The database name\n\n This must not be specified if `uri` is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_mode": {
          "description": "How to handle SSL connections",
          "anyOf": [
            {
              "$ref": "#/definitions/PgSslMode"
            },
            {
              "type": "null"
            }
          ]
        },
        "ssl_ca": {
          "description": "The PEM-encoded root certificate for SSL connections\n\n This must not be specified if the `ssl_ca_file` option is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_ca_file": {
          "description": "Path to the root certificate for SSL connections\n\n This must not be specified if the `ssl_ca` option is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_certificate": {
          "description": "The PEM-encoded client certificate for SSL connections\n\n This must not be specified if the `ssl_certificate_file` option is\n specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_certificate_file": {
          "description": "Path to the client certificate for SSL connections\n\n This must not be specified if the `ssl_certificate` option is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_key": {
          "description": "The PEM-encoded client key for SSL connections\n\n This must not be specified if the `ssl_key_file` option is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "ssl_key_file": {
          "description": "Path to the client key for SSL connections\n\n This must not be specified if the `ssl_key` option is specified.",
          "type": [
            "string",
            "null"
          ]
        },
        "max_connections": {
          "description": "Set the maximum number of connections the pool should maintain",
          "type": "integer",
          "format": "uint32",
          "minimum": 1,
          "default": 10
        },
        "min_connections": {
          "description": "Set the minimum number of connections the pool should maintain",
          "type": "integer",
          "format": "uint32",
          "minimum": 0,
          "default": 0
        },
        "connect_timeout": {
          "description": "Set the amount of time to attempt connecting to the database",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 30
        },
        "idle_timeout": {
          "description": "Set a maximum idle duration for individual connections",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0,
          "default": 600
        },
        "max_lifetime": {
          "description": "Set the maximum lifetime of individual connections",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 1800
        }
      }
    },
    "Hostname": {
      "type": "string",
      "format": "hostname"
    },
    "PgSslMode": {
      "description": "Options for controlling the level of protection provided for PostgreSQL SSL\n connections.",
      "oneOf": [
        {
          "description": "Only try a non-SSL connection.",
          "type": "string",
          "const": "disable"
        },
        {
          "description": "First try a non-SSL connection; if that fails, try an SSL connection.",
          "type": "string",
          "const": "allow"
        },
        {
          "description": "First try an SSL connection; if that fails, try a non-SSL connection.",
          "type": "string",
          "const": "prefer"
        },
        {
          "description": "Only try an SSL connection. If a root CA file is present, verify the\n connection in the same way as if `VerifyCa` was specified.",
          "type": "string",
          "const": "require"
        },
        {
          "description": "Only try an SSL connection, and verify that the server certificate is\n issued by a trusted certificate authority (CA).",
          "type": "string",
          "const": "verify-ca"
        },
        {
          "description": "Only try an SSL connection; verify that the server certificate is issued\n by a trusted CA and that the requested server host name matches that\n in the certificate.",
          "type": "string",
          "const": "verify-full"
        }
      ]
    },
    "TelemetryConfig": {
      "description": "Configuration related to sending monitoring data",
      "type": "object",
      "properties": {
        "tracing": {
          "description": "Configuration related to exporting traces",
          "allOf": [
            {
              "$ref": "#/definitions/TracingConfig"
            }
          ]
        },
        "metrics": {
          "description": "Configuration related to exporting metrics",
          "allOf": [
            {
              "$ref": "#/definitions/MetricsConfig"
            }
          ]
        },
        "sentry": {
          "description": "Configuration related to the Sentry integration",
          "allOf": [
            {
              "$ref": "#/definitions/SentryConfig"
            }
          ]
        }
      }
    },
    "TracingConfig": {
      "description": "Configuration related to exporting traces",
      "type": "object",
      "properties": {
        "exporter": {
          "description": "Exporter to use when exporting traces",
          "default": "none",
          "allOf": [
            {
              "$ref": "#/definitions/TracingExporterKind"
            }
          ]
        },
        "endpoint": {
          "description": "OTLP exporter: OTLP over HTTP compatible endpoint",
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "default": "https://localhost:4318"
        },
        "propagators": {
          "description": "List of propagation formats to use for incoming and outgoing requests",
          "type": "array",
          "items": {
            "$ref": "#/definitions/Propagator"
          },
          "default": []
        },
        "sample_rate": {
          "description": "Sample rate for traces\n\n Defaults to `1.0` if not set.",
          "type": [
            "number",
            "null"
          ],
          "format": "double",
          "examples": [
            0.5
          ],
          "minimum": 0.0,
          "maximum": 1.0
        }
      }
    },
    "TracingExporterKind": {
      "description": "Exporter to use when exporting traces",
      "oneOf": [
        {
          "description": "Don't export traces",
          "type": "string",
          "const": "none"
        },
        {
          "description": "Export traces to the standard output. Only useful for debugging",
          "type": "string",
          "const": "stdout"
        },
        {
          "description": "Export traces to an OpenTelemetry protocol compatible endpoint",
          "type": "string",
          "const": "otlp"
        }
      ]
    },
    "Propagator": {
      "description": "Propagation format for incoming and outgoing requests",
      "oneOf": [
        {
          "description": "Propagate according to the W3C Trace Context specification",
          "type": "string",
          "const": "tracecontext"
        },
        {
          "description": "Propagate according to the W3C Baggage specification",
          "type": "string",
          "const": "baggage"
        },
        {
          "description": "Propagate trace context with Jaeger compatible headers",
          "type": "string",
          "const": "jaeger"
        }
      ]
    },
    "MetricsConfig": {
      "description": "Configuration related to exporting metrics",
      "type": "object",
      "properties": {
        "exporter": {
          "description": "Exporter to use when exporting metrics",
          "default": "none",
          "allOf": [
            {
              "$ref": "#/definitions/MetricsExporterKind"
            }
          ]
        },
        "endpoint": {
          "description": "OTLP exporter: OTLP over HTTP compatible endpoint",
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "default": "https://localhost:4318"
        }
      }
    },
    "MetricsExporterKind": {
      "description": "Exporter to use when exporting metrics",
      "oneOf": [
        {
          "description": "Don't export metrics",
          "type": "string",
          "const": "none"
        },
        {
          "description": "Export metrics to stdout. Only useful for debugging",
          "type": "string",
          "const": "stdout"
        },
        {
          "description": "Export metrics to an OpenTelemetry protocol compatible endpoint",
          "type": "string",
          "const": "otlp"
        },
        {
          "description": "Export metrics via Prometheus. An HTTP listener with the `prometheus`\n resource must be setup to expose the Promethes metrics.",
          "type": "string",
          "const": "prometheus"
        }
      ]
    },
    "SentryConfig": {
      "description": "Configuration related to the Sentry integration",
      "type": "object",
      "properties": {
        "dsn": {
          "description": "Sentry DSN",
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "examples": [
            "https://public@host:port/1"
          ]
        },
        "environment": {
          "description": "Environment to use when sending events to Sentry\n\n Defaults to `production` if not set.",
          "type": [
            "string",
            "null"
          ],
          "examples": [
            "production"
          ]
        },
        "sample_rate": {
          "description": "Sample rate for event submissions\n\n Defaults to `1.0` if not set.",
          "type": [
            "number",
            "null"
          ],
          "format": "float",
          "examples": [
            0.5
          ],
          "minimum": 0.0,
          "maximum": 1.0
        },
        "traces_sample_rate": {
          "description": "Sample rate for tracing transactions\n\n Defaults to `0.0` if not set.",
          "type": [
            "number",
            "null"
          ],
          "format": "float",
          "examples": [
            0.5
          ],
          "minimum": 0.0,
          "maximum": 1.0
        }
      }
    },
    "TemplatesConfig": {
      "description": "Configuration related to templates",
      "type": "object",
      "properties": {
        "path": {
          "description": "Path to the folder which holds the templates",
          "type": [
            "string",
            "null"
          ]
        },
        "assets_manifest": {
          "description": "Path to the assets manifest",
          "type": [
            "string",
            "null"
          ]
        },
        "translations_path": {
          "description": "Path to the translations",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "EmailConfig": {
      "description": "Configuration related to sending emails",
      "type": "object",
      "properties": {
        "from": {
          "description": "Email address to use as From when sending emails",
          "type": "string",
          "format": "email",
          "default": "\"Authentication Service\" <root@localhost>"
        },
        "reply_to": {
          "description": "Email address to use as Reply-To when sending emails",
          "type": "string",
          "format": "email",
          "default": "\"Authentication Service\" <root@localhost>"
        },
        "transport": {
          "description": "What backend should be used when sending emails",
          "allOf": [
            {
              "$ref": "#/definitions/EmailTransportKind"
            }
          ]
        },
        "mode": {
          "description": "SMTP transport: Connection mode to the relay",
          "anyOf": [
            {
              "$ref": "#/definitions/EmailSmtpMode"
            },
            {
              "type": "null"
            }
          ]
        },
        "hostname": {
          "description": "SMTP transport: Hostname to connect to",
          "anyOf": [
            {
              "$ref": "#/definitions/Hostname"
            },
            {
              "type": "null"
            }
          ]
        },
        "port": {
          "description": "SMTP transport: Port to connect to. Default is 25 for plain, 465 for TLS\n and 587 for `StartTLS`",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint16",
          "minimum": 1,
          "maximum": 65535
        },
        "username": {
          "description": "SMTP transport: Username for use to authenticate when connecting to the\n SMTP server\n\n Must be set if the `password` field is set",
          "type": [
            "string",
            "null"
          ]
        },
        "password": {
          "description": "SMTP transport: Password for use to authenticate when connecting to the\n SMTP server\n\n Must be set if the `username` field is set",
          "type": [
            "string",
            "null"
          ]
        },
        "command": {
          "description": "Sendmail transport: Command to use to send emails",
          "type": [
            "string",
            "null"
          ],
          "default": "sendmail"
        }
      },
      "required": [
        "transport"
      ]
    },
    "EmailTransportKind": {
      "description": "What backend should be used when sending emails",
      "oneOf": [
        {
          "description": "Don't send emails anywhere",
          "type": "string",
          "const": "blackhole"
        },
        {
          "description": "Send emails via an SMTP relay",
          "type": "string",
          "const": "smtp"
        },
        {
          "description": "Send emails by calling sendmail",
          "type": "string",
          "const": "sendmail"
        }
      ]
    },
    "EmailSmtpMode": {
      "description": "Encryption mode to use",
      "oneOf": [
        {
          "description": "Plain text",
          "type": "string",
          "const": "plain"
        },
        {
          "description": "`StartTLS` (starts as plain text then upgrade to TLS)",
          "type": "string",
          "const": "starttls"
        },
        {
          "description": "TLS",
          "type": "string",
          "const": "tls"
        }
      ]
    },
    "SecretsConfig": {
      "description": "Application secrets",
      "type": "object",
      "properties": {
        "encryption_file": {
          "description": "File containing the encryption key for secure cookies.",
          "type": [
            "string",
            "null"
          ]
        },
        "encryption": {
          "description": "Encryption key for secure cookies.",
          "type": [
            "string",
            "null"
          ],
          "examples": [
            "0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"
          ],
          "pattern": "[0-9a-fA-F]{64}"
        },
        "keys": {
          "description": "List of private keys to use for signing and encrypting payloads.",
          "type": [
            "array",
            "null"
          ],
          "items": {
            "$ref": "#/definitions/KeyConfig"
          }
        },
        "keys_dir": {
          "description": "Directory of private keys to use for signing and encrypting payloads.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "KeyConfig": {
      "description": "A single key with its key ID and optional password.",
      "type": "object",
      "properties": {
        "kid": {
          "description": "The key ID `kid` of the key as used by JWKs.\n\n If not given, `kid` will be the key’s RFC 7638 JWK Thumbprint.",
          "type": [
            "string",
            "null"
          ]
        },
        "password_file": {
          "type": [
            "string",
            "null"
          ]
        },
        "password": {
          "type": [
            "string",
            "null"
          ]
        },
        "key_file": {
          "type": [
            "string",
            "null"
          ]
        },
        "key": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "PasswordsConfig": {
      "description": "User password hashing config",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Whether password-based authentication is enabled",
          "type": "boolean",
          "default": true
        },
        "schemes": {
          "description": "The hashing schemes to use for hashing and validating passwords\n\n The hashing scheme with the highest version number will be used for\n hashing new passwords.",
          "type": "array",
          "items": {
            "$ref": "#/definitions/HashingScheme"
          },
          "default": [
            {
              "version": 1,
              "algorithm": "argon2id"
            }
          ]
        },
        "minimum_complexity": {
          "description": "Score between 0 and 4 determining the minimum allowed password\n complexity. Scores are based on the ESTIMATED number of guesses\n needed to guess the password.\n\n - 0: less than 10^2 (100)\n - 1: less than 10^4 (10'000)\n - 2: less than 10^6 (1'000'000)\n - 3: less than 10^8 (100'000'000)\n - 4: any more than that",
          "type": "integer",
          "format": "uint8",
          "minimum": 0,
          "maximum": 255,
          "default": 3
        }
      }
    },
    "HashingScheme": {
      "description": "Parameters for a password hashing scheme",
      "type": "object",
      "properties": {
        "version": {
          "description": "The version of the hashing scheme. They must be unique, and the highest\n version will be used for hashing new passwords.",
          "type": "integer",
          "format": "uint16",
          "minimum": 0,
          "maximum": 65535
        },
        "algorithm": {
          "description": "The hashing algorithm to use",
          "allOf": [
            {
              "$ref": "#/definitions/Algorithm"
            }
          ]
        },
        "unicode_normalization": {
          "description": "Whether to apply Unicode normalization to the password before hashing\n\n Defaults to `false`, and generally recommended to stay false. This is\n although recommended when importing password hashs from Synapse, as it\n applies an NFKC normalization to the password before hashing it.",
          "type": "boolean"
        },
        "cost": {
          "description": "Cost for the bcrypt algorithm",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint32",
          "minimum": 0,
          "default": 12
        },
        "secret": {
          "description": "An optional secret to use when hashing passwords. This makes it harder\n to brute-force the passwords in case of a database leak.",
          "type": [
            "string",
            "null"
          ]
        },
        "secret_file": {
          "description": "Same as `secret`, but read from a file.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "version",
        "algorithm"
      ]
    },
    "Algorithm": {
      "description": "A hashing algorithm",
      "oneOf": [
        {
          "description": "bcrypt",
          "type": "string",
          "const": "bcrypt"
        },
        {
          "description": "argon2id",
          "type": "string",
          "const": "argon2id"
        },
        {
          "description": "PBKDF2",
          "type": "string",
          "const": "pbkdf2"
        }
      ]
    },
    "MatrixConfig": {
      "description": "Configuration related to the Matrix homeserver",
      "type": "object",
      "properties": {
        "kind": {
          "description": "The kind of homeserver it is.",
          "default": "synapse",
          "allOf": [
            {
              "$ref": "#/definitions/HomeserverKind"
            }
          ]
        },
        "homeserver": {
          "description": "The server name of the homeserver.",
          "type": "string",
          "default": "localhost:8008"
        },
        "secret_file": {
          "type": [
            "string",
            "null"
          ]
        },
        "secret": {
          "type": [
            "string",
            "null"
          ]
        },
        "endpoint": {
          "description": "The base URL of the homeserver's client API",
          "type": "string",
          "format": "uri",
          "default": "http://localhost:8008/"
        }
      }
    },
    "HomeserverKind": {
      "description": "The kind of homeserver it is.",
      "oneOf": [
        {
          "description": "Homeserver is Synapse, version 1.135.0 or newer",
          "type": "string",
          "const": "synapse"
        },
        {
          "description": "Homeserver is Synapse, version 1.135.0 or newer, in read-only mode\n\n This is meant for testing rolling out Matrix Authentication Service with\n no risk of writing data to the homeserver.",
          "type": "string",
          "const": "synapse_read_only"
        },
        {
          "description": "Homeserver is Synapse, using the legacy API",
          "type": "string",
          "const": "synapse_legacy"
        },
        {
          "description": "Homeserver is Synapse, with the modern API available (>= 1.135.0)",
          "type": "string",
          "const": "synapse_modern"
        }
      ]
    },
    "PolicyConfig": {
      "description": "Application secrets",
      "type": "object",
      "properties": {
        "wasm_module": {
          "description": "Path to the WASM module",
          "type": "string"
        },
        "client_registration_entrypoint": {
          "description": "Entrypoint to use when evaluating client registrations",
          "type": "string"
        },
        "register_entrypoint": {
          "description": "Entrypoint to use when evaluating user registrations",
          "type": "string"
        },
        "authorization_grant_entrypoint": {
          "description": "Entrypoint to use when evaluating authorization grants",
          "type": "string"
        },
        "compat_login_entrypoint": {
          "description": "Entrypoint to use when evaluating compatibility logins",
          "type": "string"
        },
        "password_entrypoint": {
          "description": "Entrypoint to use when changing password",
          "type": "string"
        },
        "email_entrypoint": {
          "description": "Entrypoint to use when adding an email address",
          "type": "string"
        },
        "data": {
          "description": "Arbitrary data to pass to the policy"
        }
      }
    },
    "RateLimitingConfig": {
      "description": "Configuration related to sending emails",
      "type": "object",
      "properties": {
        "account_recovery": {
          "description": "Account Recovery-specific rate limits",
          "default": {
            "per_ip": {
              "burst": 3,
              "per_second": 0.0008333333333333334
            },
            "per_address": {
              "burst": 3,
              "per_second": 0.0002777777777777778
            }
          },
          "allOf": [
            {
              "$ref": "#/definitions/AccountRecoveryRateLimitingConfig"
            }
          ]
        },
        "login": {
          "description": "Login-specific rate limits",
          "default": {
            "per_ip": {
              "burst": 3,
              "per_second": 0.05
            },
            "per_account": {
              "burst": 1800,
              "per_second": 0.5
            }
          },
          "allOf": [
            {
              "$ref": "#/definitions/LoginRateLimitingConfig"
            }
          ]
        },
        "registration": {
          "description": "Controls how many registrations attempts are permitted\n based on source address.",
          "default": {
            "burst": 3,
            "per_second": 0.0008333333333333334
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "email_authentication": {
          "description": "Email authentication-specific rate limits",
          "default": {
            "per_ip": {
              "burst": 5,
              "per_second": 0.016666666666666666
            },
            "per_address": {
              "burst": 3,
              "per_second": 0.0002777777777777778
            },
            "emails_per_session": {
              "burst": 2,
              "per_second": 0.0033333333333333335
            },
            "attempt_per_session": {
              "burst": 10,
              "per_second": 0.016666666666666666
            }
          },
          "allOf": [
            {
              "$ref": "#/definitions/EmailauthenticationRateLimitingConfig"
            }
          ]
        }
      }
    },
    "AccountRecoveryRateLimitingConfig": {
      "type": "object",
      "properties": {
        "per_ip": {
          "description": "Controls how many account recovery attempts are permitted\n based on source IP address.\n This can protect against causing e-mail spam to many targets.\n\n Note: this limit also applies to re-sends.",
          "default": {
            "burst": 3,
            "per_second": 0.0008333333333333334
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "per_address": {
          "description": "Controls how many account recovery attempts are permitted\n based on the e-mail address entered into the recovery form.\n This can protect against causing e-mail spam to one target.\n\n Note: this limit also applies to re-sends.",
          "default": {
            "burst": 3,
            "per_second": 0.0002777777777777778
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        }
      }
    },
    "RateLimiterConfiguration": {
      "type": "object",
      "properties": {
        "burst": {
          "description": "A one-off burst of actions that the user can perform\n in one go without waiting.",
          "type": "integer",
          "format": "uint32",
          "minimum": 1
        },
        "per_second": {
          "description": "How quickly the allowance replenishes, in number of actions per second.\n Can be fractional to replenish slower.",
          "type": "number",
          "format": "double"
        }
      },
      "required": [
        "burst",
        "per_second"
      ]
    },
    "LoginRateLimitingConfig": {
      "type": "object",
      "properties": {
        "per_ip": {
          "description": "Controls how many login attempts are permitted\n based on source IP address.\n This can protect against brute force login attempts.\n\n Note: this limit also applies to password checks when a user attempts to\n change their own password.",
          "default": {
            "burst": 3,
            "per_second": 0.05
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "per_account": {
          "description": "Controls how many login attempts are permitted\n based on the account that is being attempted to be logged into.\n This can protect against a distributed brute force attack\n but should be set high enough to prevent someone's account being\n casually locked out.\n\n Note: this limit also applies to password checks when a user attempts to\n change their own password.",
          "default": {
            "burst": 1800,
            "per_second": 0.5
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        }
      }
    },
    "EmailauthenticationRateLimitingConfig": {
      "type": "object",
      "properties": {
        "per_ip": {
          "description": "Controls how many email authentication attempts are permitted\n based on the source IP address.\n This can protect against causing e-mail spam to many targets.",
          "default": {
            "burst": 5,
            "per_second": 0.016666666666666666
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "per_address": {
          "description": "Controls how many email authentication attempts are permitted\n based on the e-mail address entered into the authentication form.\n This can protect against causing e-mail spam to one target.\n\n Note: this limit also applies to re-sends.",
          "default": {
            "burst": 3,
            "per_second": 0.0002777777777777778
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "emails_per_session": {
          "description": "Controls how many authentication emails are permitted to be sent per\n authentication session. This ensures not too many authentication codes\n are created for the same authentication session.",
          "default": {
            "burst": 2,
            "per_second": 0.0033333333333333335
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        },
        "attempt_per_session": {
          "description": "Controls how many code authentication attempts are permitted per\n authentication session. This can protect against brute-forcing the\n code.",
          "default": {
            "burst": 10,
            "per_second": 0.016666666666666666
          },
          "allOf": [
            {
              "$ref": "#/definitions/RateLimiterConfiguration"
            }
          ]
        }
      }
    },
    "UpstreamOAuth2Config": {
      "description": "Upstream OAuth 2.0 providers configuration",
      "type": "object",
      "properties": {
        "providers": {
          "description": "List of OAuth 2.0 providers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/Provider"
          }
        }
      },
      "required": [
        "providers"
      ]
    },
    "Provider": {
      "description": "Configuration for one upstream OAuth 2 provider.",
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Whether this provider is enabled.\n\n Defaults to `true`",
          "type": "boolean"
        },
        "id": {
          "description": "A ULID as per https://github.com/ulid/spec",
          "type": "string",
          "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
        },
        "synapse_idp_id": {
          "description": "The ID of the provider that was used by Synapse.\n In order to perform a Synapse-to-MAS migration, this must be specified.\n\n ## For providers that used OAuth 2.0 or OpenID Connect in Synapse\n\n ### For `oidc_providers`:\n This should be specified as `oidc-` followed by the ID that was\n configured as `idp_id` in one of the `oidc_providers` in the Synapse\n configuration.\n For example, if Synapse's configuration contained `idp_id: wombat` for\n this provider, then specify `oidc-wombat` here.\n\n ### For `oidc_config` (legacy):\n Specify `oidc` here.",
          "type": [
            "string",
            "null"
          ]
        },
        "issuer": {
          "description": "The OIDC issuer URL\n\n This is required if OIDC discovery is enabled (which is the default)",
          "type": [
            "string",
            "null"
          ]
        },
        "human_name": {
          "description": "A human-readable name for the provider, that will be shown to users",
          "type": [
            "string",
            "null"
          ]
        },
        "brand_name": {
          "description": "A brand identifier used to customise the UI, e.g. `apple`, `google`,\n `github`, etc.\n\n Values supported by the default template are:\n\n  - `apple`\n  - `google`\n  - `facebook`\n  - `github`\n  - `gitlab`\n  - `twitter`\n  - `discord`",
          "type": [
            "string",
            "null"
          ]
        },
        "client_id": {
          "description": "The client ID to use when authenticating with the provider",
          "type": "string"
        },
        "client_secret_file": {
          "description": "Path to the file containing the client secret. The client secret is used\n by the `client_secret_basic`, `client_secret_post` and\n `client_secret_jwt` authentication methods.",
          "type": [
            "string",
            "null"
          ]
        },
        "client_secret": {
          "description": "Alternative to `client_secret_file`: Reads the client secret directly\n from the config.",
          "type": [
            "string",
            "null"
          ]
        },
        "token_endpoint_auth_method": {
          "description": "The method to authenticate the client with the provider",
          "allOf": [
            {
              "$ref": "#/definitions/TokenAuthMethod"
            }
          ]
        },
        "sign_in_with_apple": {
          "description": "Additional parameters for the `sign_in_with_apple` method",
          "anyOf": [
            {
              "$ref": "#/definitions/SignInWithApple"
            },
            {
              "type": "null"
            }
          ]
        },
        "token_endpoint_auth_signing_alg": {
          "description": "The JWS algorithm to use when authenticating the client with the\n provider\n\n Used by the `client_secret_jwt` and `private_key_jwt` methods",
          "anyOf": [
            {
              "$ref": "#/definitions/JsonWebSignatureAlg"
            },
            {
              "type": "null"
            }
          ]
        },
        "id_token_signed_response_alg": {
          "description": "Expected signature for the JWT payload returned by the token\n authentication endpoint.\n\n Defaults to `RS256`.",
          "allOf": [
            {
              "$ref": "#/definitions/JsonWebSignatureAlg"
            }
          ]
        },
        "scope": {
          "description": "The scopes to request from the provider\n\n Defaults to `openid`.",
          "type": "string"
        },
        "discovery_mode": {
          "description": "How to discover the provider's configuration\n\n Defaults to `oidc`, which uses OIDC discovery with strict metadata\n verification",
          "allOf": [
            {
              "$ref": "#/definitions/DiscoveryMode"
            }
          ]
        },
        "pkce_method": {
          "description": "Whether to use proof key for code exchange (PKCE) when requesting and\n exchanging the token.\n\n Defaults to `auto`, which uses PKCE if the provider supports it.",
          "allOf": [
            {
              "$ref": "#/definitions/PkceMethod"
            }
          ]
        },
        "fetch_userinfo": {
          "description": "Whether to fetch the user profile from the userinfo endpoint,\n or to rely on the data returned in the `id_token` from the\n `token_endpoint`.\n\n Defaults to `false`.",
          "type": "boolean",
          "default": false
        },
        "userinfo_signed_response_alg": {
          "description": "Expected signature for the JWT payload returned by the userinfo\n endpoint.\n\n If not specified, the response is expected to be an unsigned JSON\n payload.",
          "anyOf": [
            {
              "$ref": "#/definitions/JsonWebSignatureAlg"
            },
            {
              "type": "null"
            }
          ]
        },
        "authorization_endpoint": {
          "description": "The URL to use for the provider's authorization endpoint\n\n Defaults to the `authorization_endpoint` provided through discovery",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "userinfo_endpoint": {
          "description": "The URL to use for the provider's userinfo endpoint\n\n Defaults to the `userinfo_endpoint` provided through discovery",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "token_endpoint": {
          "description": "The URL to use for the provider's token endpoint\n\n Defaults to the `token_endpoint` provided through discovery",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "jwks_uri": {
          "description": "The URL to use for getting the provider's public keys\n\n Defaults to the `jwks_uri` provided through discovery",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "response_mode": {
          "description": "The response mode we ask the provider to use for the callback",
          "anyOf": [
            {
              "$ref": "#/definitions/ResponseMode"
            },
            {
              "type": "null"
            }
          ]
        },
        "claims_imports": {
          "description": "How claims should be imported from the `id_token` provided by the\n provider",
          "allOf": [
            {
              "$ref": "#/definitions/ClaimsImports"
            }
          ]
        },
        "additional_authorization_parameters": {
          "description": "Additional parameters to include in the authorization request\n\n Orders of the keys are not preserved.",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "forward_login_hint": {
          "description": "Whether the `login_hint` should be forwarded to the provider in the\n authorization request.\n\n Defaults to `false`.",
          "type": "boolean",
          "default": false
        },
        "on_backchannel_logout": {
          "description": "What to do when receiving an OIDC Backchannel logout request.\n\n Defaults to `do_nothing`.",
          "allOf": [
            {
              "$ref": "#/definitions/OnBackchannelLogout"
            }
          ]
        }
      },
      "required": [
        "id",
        "client_id",
        "token_endpoint_auth_method"
      ]
    },
    "TokenAuthMethod": {
      "description": "Authentication methods used against the OAuth 2.0 provider",
      "oneOf": [
        {
          "description": "`none`: No authentication",
          "type": "string",
          "const": "none"
        },
        {
          "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic\n authorization credentials",
          "type": "string",
          "const": "client_secret_basic"
        },
        {
          "description": "`client_secret_post`: `client_id` and `client_secret` sent in the\n request body",
          "type": "string",
          "const": "client_secret_post"
        },
        {
          "description": "`client_secret_jwt`: a `client_assertion` sent in the request body and\n signed using the `client_secret`",
          "type": "string",
          "const": "client_secret_jwt"
        },
        {
          "description": "`private_key_jwt`: a `client_assertion` sent in the request body and\n signed by an asymmetric key",
          "type": "string",
          "const": "private_key_jwt"
        },
        {
          "description": "`sign_in_with_apple`: a special method for Signin with Apple",
          "type": "string",
          "const": "sign_in_with_apple"
        }
      ]
    },
    "SignInWithApple": {
      "type": "object",
      "properties": {
        "private_key_file": {
          "description": "The private key file used to sign the `id_token`",
          "type": [
            "string",
            "null"
          ]
        },
        "private_key": {
          "description": "The private key used to sign the `id_token`",
          "type": [
            "string",
            "null"
          ]
        },
        "team_id": {
          "description": "The Team ID of the Apple Developer Portal",
          "type": "string"
        },
        "key_id": {
          "description": "The key ID of the Apple Developer Portal",
          "type": "string"
        }
      },
      "required": [
        "team_id",
        "key_id"
      ]
    },
    "DiscoveryMode": {
      "description": "How to discover the provider's configuration",
      "oneOf": [
        {
          "description": "Use OIDC discovery with strict metadata verification",
          "type": "string",
          "const": "oidc"
        },
        {
          "description": "Use OIDC discovery with relaxed metadata verification",
          "type": "string",
          "const": "insecure"
        },
        {
          "description": "Use a static configuration",
          "type": "string",
          "const": "disabled"
        }
      ]
    },
    "PkceMethod": {
      "description": "Whether to use proof key for code exchange (PKCE) when requesting and\n exchanging the token.",
      "oneOf": [
        {
          "description": "Use PKCE if the provider supports it\n\n Defaults to no PKCE if provider discovery is disabled",
          "type": "string",
          "const": "auto"
        },
        {
          "description": "Always use PKCE with the S256 challenge method",
          "type": "string",
          "const": "always"
        },
        {
          "description": "Never use PKCE",
          "type": "string",
          "const": "never"
        }
      ]
    },
    "ResponseMode": {
      "description": "The response mode we ask the provider to use for the callback",
      "oneOf": [
        {
          "description": "`query`: The provider will send the response as a query string in the\n URL search parameters",
          "type": "string",
          "const": "query"
        },
        {
          "description": "`form_post`: The provider will send the response as a POST request with\n the response parameters in the request body\n\n <https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html>",
          "type": "string",
          "const": "form_post"
        }
      ]
    },
    "ClaimsImports": {
      "description": "How claims should be imported",
      "type": "object",
      "properties": {
        "subject": {
          "description": "How to determine the subject of the user",
          "allOf": [
            {
              "$ref": "#/definitions/SubjectImportPreference"
            }
          ]
        },
        "skip_confirmation": {
          "description": "Whether to skip the interactive screen prompting the user to confirm the\n attributes that are being imported. This requires `localpart.action` to\n be `require` and other attribute actions to be either `ignore`, `force`\n or `require`",
          "type": "boolean"
        },
        "localpart": {
          "description": "Import the localpart of the MXID",
          "allOf": [
            {
              "$ref": "#/definitions/LocalpartImportPreference"
            }
          ]
        },
        "displayname": {
          "description": "Import the displayname of the user.",
          "allOf": [
            {
              "$ref": "#/definitions/DisplaynameImportPreference"
            }
          ]
        },
        "email": {
          "description": "Import the email address of the user",
          "allOf": [
            {
              "$ref": "#/definitions/EmailImportPreference"
            }
          ]
        },
        "account_name": {
          "description": "Set a human-readable name for the upstream account for display purposes",
          "allOf": [
            {
              "$ref": "#/definitions/AccountNameImportPreference"
            }
          ]
        }
      }
    },
    "SubjectImportPreference": {
      "description": "What should be done for the subject attribute",
      "type": "object",
      "properties": {
        "template": {
          "description": "The Jinja2 template to use for the subject attribute\n\n If not provided, the default template is `{{ user.sub }}`",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "LocalpartImportPreference": {
      "description": "What should be done for the localpart attribute",
      "type": "object",
      "properties": {
        "action": {
          "description": "How to handle the attribute",
          "allOf": [
            {
              "$ref": "#/definitions/ImportAction"
            }
          ]
        },
        "template": {
          "description": "The Jinja2 template to use for the localpart attribute\n\n If not provided, the default template is `{{ user.preferred_username }}`",
          "type": [
            "string",
            "null"
          ]
        },
        "on_conflict": {
          "description": "How to handle conflicts on the claim, default value is `Fail`",
          "allOf": [
            {
              "$ref": "#/definitions/OnConflict"
            }
          ]
        }
      }
    },
    "ImportAction": {
      "description": "How to handle a claim",
      "oneOf": [
        {
          "description": "Ignore the claim",
          "type": "string",
          "const": "ignore"
        },
        {
          "description": "Suggest the claim value, but allow the user to change it",
          "type": "string",
          "const": "suggest"
        },
        {
          "description": "Force the claim value, but don't fail if it is missing",
          "type": "string",
          "const": "force"
        },
        {
          "description": "Force the claim value, and fail if it is missing",
          "type": "string",
          "const": "require"
        }
      ]
    },
    "OnConflict": {
      "description": "How to handle an existing localpart claim",
      "oneOf": [
        {
          "description": "Fails the upstream OAuth 2.0 login on conflict",
          "type": "string",
          "const": "fail"
        },
        {
          "description": "Adds the upstream OAuth 2.0 identity link, regardless of whether there\n is an existing link or not",
          "type": "string",
          "const": "add"
        },
        {
          "description": "Replace any existing upstream OAuth 2.0 identity link",
          "type": "string",
          "const": "replace"
        },
        {
          "description": "Adds the upstream OAuth 2.0 identity link *only* if there is no existing\n link for this provider on the matching user",
          "type": "string",
          "const": "set"
        }
      ]
    },
    "DisplaynameImportPreference": {
      "description": "What should be done for the displayname attribute",
      "type": "object",
      "properties": {
        "action": {
          "description": "How to handle the attribute",
          "allOf": [
            {
              "$ref": "#/definitions/ImportAction"
            }
          ]
        },
        "template": {
          "description": "The Jinja2 template to use for the displayname attribute\n\n If not provided, the default template is `{{ user.name }}`",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "EmailImportPreference": {
      "description": "What should be done with the email attribute",
      "type": "object",
      "properties": {
        "action": {
          "description": "How to handle the claim",
          "allOf": [
            {
              "$ref": "#/definitions/ImportAction"
            }
          ]
        },
        "template": {
          "description": "The Jinja2 template to use for the email address attribute\n\n If not provided, the default template is `{{ user.email }}`",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "AccountNameImportPreference": {
      "description": "What should be done for the account name attribute",
      "type": "object",
      "properties": {
        "template": {
          "description": "The Jinja2 template to use for the account name. This name is only used\n for display purposes.\n\n If not provided, it will be ignored.",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "OnBackchannelLogout": {
      "description": "What to do when receiving an OIDC Backchannel logout request.",
      "oneOf": [
        {
          "description": "Do nothing",
          "type": "string",
          "const": "do_nothing"
        },
        {
          "description": "Only log out the MAS 'browser session' started by this OIDC session",
          "type": "string",
          "const": "logout_browser_only"
        },
        {
          "description": "Log out all sessions started by this OIDC session, including MAS\n 'browser sessions' and client sessions",
          "type": "string",
          "const": "logout_all"
        }
      ]
    },
    "BrandingConfig": {
      "description": "Configuration section for tweaking the branding of the service",
      "type": "object",
      "properties": {
        "service_name": {
          "description": "A human-readable name. Defaults to the server's address.",
          "type": [
            "string",
            "null"
          ]
        },
        "policy_uri": {
          "description": "Link to a privacy policy, displayed in the footer of web pages and\n emails. It is also advertised to clients through the `op_policy_uri`\n OIDC provider metadata.",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "tos_uri": {
          "description": "Link to a terms of service document, displayed in the footer of web\n pages and emails. It is also advertised to clients through the\n `op_tos_uri` OIDC provider metadata.",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "imprint": {
          "description": "Legal imprint, displayed in the footer in the footer of web pages and\n emails.",
          "type": [
            "string",
            "null"
          ]
        },
        "logo_uri": {
          "description": "Logo displayed in some web pages.",
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        }
      }
    },
    "CaptchaConfig": {
      "description": "Configuration section to setup CAPTCHA protection on a few operations",
      "type": "object",
      "properties": {
        "service": {
          "description": "Which service should be used for CAPTCHA protection",
          "anyOf": [
            {
              "$ref": "#/definitions/CaptchaServiceKind"
            },
            {
              "type": "null"
            }
          ]
        },
        "site_key": {
          "description": "The site key to use",
          "type": [
            "string",
            "null"
          ]
        },
        "secret_key": {
          "description": "The secret key to use",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "CaptchaServiceKind": {
      "description": "Which service should be used for CAPTCHA protection",
      "oneOf": [
        {
          "description": "Use Google's reCAPTCHA v2 API",
          "type": "string",
          "const": "recaptcha_v2"
        },
        {
          "description": "Use Cloudflare Turnstile",
          "type": "string",
          "const": "cloudflare_turnstile"
        },
        {
          "description": "Use ``HCaptcha``",
          "type": "string",
          "const": "hcaptcha"
        }
      ]
    },
    "AccountConfig": {
      "description": "Configuration section to configure features related to account management",
      "type": "object",
      "properties": {
        "email_change_allowed": {
          "description": "Whether users are allowed to change their email addresses. Defaults to\n `true`.",
          "type": "boolean"
        },
        "displayname_change_allowed": {
          "description": "Whether users are allowed to change their display names. Defaults to\n `true`.\n\n This should be in sync with the policy in the homeserver configuration.",
          "type": "boolean"
        },
        "password_registration_enabled": {
          "description": "Whether to enable self-service password registration. Defaults to\n `false` if password authentication is enabled.\n\n This has no effect if password login is disabled.",
          "type": "boolean"
        },
        "password_registration_email_required": {
          "description": "Whether self-service password registrations require a valid email.\n Defaults to `true`.\n\n This has no effect if password registration is disabled.",
          "type": "boolean"
        },
        "password_change_allowed": {
          "description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\n This has no effect if password login is disabled.",
          "type": "boolean"
        },
        "password_recovery_enabled": {
          "description": "Whether email-based password recovery is enabled. Defaults to `false`.\n\n This has no effect if password login is disabled.",
          "type": "boolean"
        },
        "account_deactivation_allowed": {
          "description": "Whether users are allowed to delete their own account. Defaults to\n `true`.",
          "type": "boolean"
        },
        "login_with_email_allowed": {
          "description": "Whether users can log in with their email address. Defaults to `false`.\n\n This has no effect if password login is disabled.",
          "type": "boolean"
        },
        "registration_token_required": {
          "description": "Whether registration tokens are required for password registrations.\n Defaults to `false`.\n\n When enabled, users must provide a valid registration token during\n password registration. This has no effect if password registration\n is disabled.",
          "type": "boolean"
        }
      }
    },
    "ExperimentalConfig": {
      "description": "Configuration sections for experimental options\n\n Do not change these options unless you know what you are doing.",
      "type": "object",
      "properties": {
        "access_token_ttl": {
          "description": "Time-to-live of access tokens in seconds. Defaults to 5 minutes.",
          "type": "integer",
          "format": "uint64",
          "minimum": 60,
          "maximum": 86400
        },
        "compat_token_ttl": {
          "description": "Time-to-live of compatibility access tokens in seconds. Defaults to 5\n minutes.",
          "type": "integer",
          "format": "uint64",
          "minimum": 60,
          "maximum": 86400
        },
        "inactive_session_expiration": {
          "description": "Experimetal feature to automatically expire inactive sessions\n\n Disabled by default",
          "anyOf": [
            {
              "$ref": "#/definitions/InactiveSessionExpirationConfig"
            },
            {
              "type": "null"
            }
          ]
        },
        "plan_management_iframe_uri": {
          "description": "Experimental feature to show a plan management tab and iframe.\n This value is passed through \"as is\" to the client without any\n validation.",
          "type": [
            "string",
            "null"
          ]
        },
        "session_limit": {
          "description": "Experimental feature to limit the number of application sessions per\n user.\n\n Disabled by default.",
          "anyOf": [
            {
              "$ref": "#/definitions/SessionLimitConfig"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "InactiveSessionExpirationConfig": {
      "description": "Configuration options for the inactive session expiration feature",
      "type": "object",
      "properties": {
        "ttl": {
          "description": "Time after which an inactive session is automatically finished",
          "type": "integer",
          "format": "uint64",
          "minimum": 600,
          "maximum": 7776000
        },
        "expire_compat_sessions": {
          "description": "Should compatibility sessions expire after inactivity",
          "type": "boolean",
          "default": true
        },
        "expire_oauth_sessions": {
          "description": "Should OAuth 2.0 sessions expire after inactivity",
          "type": "boolean",
          "default": true
        },
        "expire_user_sessions": {
          "description": "Should user sessions expire after inactivity",
          "type": "boolean",
          "default": true
        }
      },
      "required": [
        "ttl"
      ]
    },
    "SessionLimitConfig": {
      "description": "Configuration options for the session limit feature",
      "type": "object",
      "properties": {
        "soft_limit": {
          "type": "integer",
          "format": "uint64",
          "minimum": 1
        },
        "hard_limit": {
          "type": "integer",
          "format": "uint64",
          "minimum": 1
        }
      },
      "required": [
        "soft_limit",
        "hard_limit"
      ]
    }
  }
}