You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Make the access tokens TTL configurable
This commit is contained in:
@ -18,7 +18,9 @@ use anyhow::Context;
|
||||
use clap::Parser;
|
||||
use itertools::Itertools;
|
||||
use mas_config::AppConfig;
|
||||
use mas_handlers::{AppState, CookieManager, HttpClientFactory, MatrixHomeserver, MetadataCache};
|
||||
use mas_handlers::{
|
||||
AppState, CookieManager, HttpClientFactory, MatrixHomeserver, MetadataCache, SiteConfig,
|
||||
};
|
||||
use mas_listener::{server::Server, shutdown::ShutdownStream};
|
||||
use mas_matrix_synapse::SynapseConnection;
|
||||
use mas_router::UrlBuilder;
|
||||
@ -137,6 +139,11 @@ impl Options {
|
||||
http_client_factory.clone(),
|
||||
);
|
||||
|
||||
let site_config = SiteConfig {
|
||||
access_token_ttl: config.hack.access_token_ttl,
|
||||
compat_token_ttl: config.hack.compat_token_ttl,
|
||||
};
|
||||
|
||||
// Explicitly the config to properly zeroize secret keys
|
||||
drop(config);
|
||||
|
||||
@ -159,6 +166,7 @@ impl Options {
|
||||
graphql_schema,
|
||||
http_client_factory,
|
||||
password_manager,
|
||||
site_config,
|
||||
conn_acquisition_histogram: None,
|
||||
};
|
||||
s.init_metrics()?;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -19,33 +19,42 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
|
||||
use super::ConfigurationSection;
|
||||
use crate::ConfigurationSection;
|
||||
|
||||
fn default_ttl() -> Duration {
|
||||
Duration::hours(1)
|
||||
fn default_token_ttl() -> Duration {
|
||||
Duration::minutes(5)
|
||||
}
|
||||
|
||||
/// Configuration related to Cross-Site Request Forgery protections
|
||||
/// Configuration sections for miscellaneous options
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CsrfConfig {
|
||||
/// Time-to-live of a CSRF token in seconds
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
|
||||
pub struct HackConfig {
|
||||
/// Time-to-live of access tokens in seconds
|
||||
#[schemars(with = "u64", range(min = 60, max = 86400))]
|
||||
#[serde(default = "default_ttl")]
|
||||
#[serde(default = "default_token_ttl")]
|
||||
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
|
||||
pub ttl: Duration,
|
||||
pub access_token_ttl: Duration,
|
||||
|
||||
/// Time-to-live of compatibility access tokens in seconds
|
||||
#[schemars(with = "u64", range(min = 60, max = 86400))]
|
||||
#[serde(default = "default_token_ttl")]
|
||||
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
|
||||
pub compat_token_ttl: Duration,
|
||||
}
|
||||
|
||||
impl Default for CsrfConfig {
|
||||
impl Default for HackConfig {
|
||||
fn default() -> Self {
|
||||
Self { ttl: default_ttl() }
|
||||
Self {
|
||||
access_token_ttl: default_token_ttl(),
|
||||
compat_token_ttl: default_token_ttl(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ConfigurationSection for CsrfConfig {
|
||||
impl ConfigurationSection for HackConfig {
|
||||
fn path() -> &'static str {
|
||||
"csrf"
|
||||
"hack"
|
||||
}
|
||||
|
||||
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
|
||||
@ -59,29 +68,3 @@ impl ConfigurationSection for CsrfConfig {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use figment::Jail;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn load_config() {
|
||||
Jail::expect_with(|jail| {
|
||||
jail.create_file(
|
||||
"config.yaml",
|
||||
r#"
|
||||
csrf:
|
||||
ttl: 1800
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let config = CsrfConfig::load_from_file("config.yaml")?;
|
||||
|
||||
assert_eq!(config.ttl, Duration::minutes(30));
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
@ -18,9 +18,9 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod clients;
|
||||
mod csrf;
|
||||
mod database;
|
||||
mod email;
|
||||
mod hack;
|
||||
mod http;
|
||||
mod matrix;
|
||||
mod passwords;
|
||||
@ -32,9 +32,9 @@ mod upstream_oauth2;
|
||||
|
||||
pub use self::{
|
||||
clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
|
||||
csrf::CsrfConfig,
|
||||
database::{ConnectConfig as DatabaseConnectConfig, DatabaseConfig},
|
||||
email::{EmailConfig, EmailSmtpMode, EmailTransportConfig},
|
||||
hack::HackConfig,
|
||||
http::{
|
||||
BindConfig as HttpBindConfig, HttpConfig, ListenerConfig as HttpListenerConfig,
|
||||
Resource as HttpResource, TlsConfig as HttpTlsConfig, UnixOrTcp,
|
||||
@ -81,10 +81,6 @@ pub struct RootConfig {
|
||||
#[serde(default)]
|
||||
pub templates: TemplatesConfig,
|
||||
|
||||
/// Configuration related to Cross-Site Request Forgery protections
|
||||
#[serde(default)]
|
||||
pub csrf: CsrfConfig,
|
||||
|
||||
/// Configuration related to sending emails
|
||||
#[serde(default)]
|
||||
pub email: EmailConfig,
|
||||
@ -106,6 +102,10 @@ pub struct RootConfig {
|
||||
/// Configuration related to upstream OAuth providers
|
||||
#[serde(default)]
|
||||
pub upstream_oauth2: UpstreamOAuth2Config,
|
||||
|
||||
/// Miscellaneous configuration options
|
||||
#[serde(default)]
|
||||
pub hack: HackConfig,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -124,13 +124,13 @@ impl ConfigurationSection for RootConfig {
|
||||
database: DatabaseConfig::generate(&mut rng).await?,
|
||||
telemetry: TelemetryConfig::generate(&mut rng).await?,
|
||||
templates: TemplatesConfig::generate(&mut rng).await?,
|
||||
csrf: CsrfConfig::generate(&mut rng).await?,
|
||||
email: EmailConfig::generate(&mut rng).await?,
|
||||
passwords: PasswordsConfig::generate(&mut rng).await?,
|
||||
secrets: SecretsConfig::generate(&mut rng).await?,
|
||||
matrix: MatrixConfig::generate(&mut rng).await?,
|
||||
policy: PolicyConfig::generate(&mut rng).await?,
|
||||
upstream_oauth2: UpstreamOAuth2Config::generate(&mut rng).await?,
|
||||
hack: HackConfig::generate(&mut rng).await?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -142,12 +142,12 @@ impl ConfigurationSection for RootConfig {
|
||||
telemetry: TelemetryConfig::test(),
|
||||
templates: TemplatesConfig::test(),
|
||||
passwords: PasswordsConfig::test(),
|
||||
csrf: CsrfConfig::test(),
|
||||
email: EmailConfig::test(),
|
||||
secrets: SecretsConfig::test(),
|
||||
matrix: MatrixConfig::test(),
|
||||
policy: PolicyConfig::test(),
|
||||
upstream_oauth2: UpstreamOAuth2Config::test(),
|
||||
hack: HackConfig::test(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,9 +165,6 @@ pub struct AppConfig {
|
||||
#[serde(default)]
|
||||
pub templates: TemplatesConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub csrf: CsrfConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub email: EmailConfig,
|
||||
|
||||
@ -180,6 +177,9 @@ pub struct AppConfig {
|
||||
|
||||
#[serde(default)]
|
||||
pub policy: PolicyConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub hack: HackConfig,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -196,12 +196,12 @@ impl ConfigurationSection for AppConfig {
|
||||
http: HttpConfig::generate(&mut rng).await?,
|
||||
database: DatabaseConfig::generate(&mut rng).await?,
|
||||
templates: TemplatesConfig::generate(&mut rng).await?,
|
||||
csrf: CsrfConfig::generate(&mut rng).await?,
|
||||
email: EmailConfig::generate(&mut rng).await?,
|
||||
passwords: PasswordsConfig::generate(&mut rng).await?,
|
||||
secrets: SecretsConfig::generate(&mut rng).await?,
|
||||
matrix: MatrixConfig::generate(&mut rng).await?,
|
||||
policy: PolicyConfig::generate(&mut rng).await?,
|
||||
hack: HackConfig::generate(&mut rng).await?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -211,11 +211,11 @@ impl ConfigurationSection for AppConfig {
|
||||
database: DatabaseConfig::test(),
|
||||
templates: TemplatesConfig::test(),
|
||||
passwords: PasswordsConfig::test(),
|
||||
csrf: CsrfConfig::test(),
|
||||
email: EmailConfig::test(),
|
||||
secrets: SecretsConfig::test(),
|
||||
matrix: MatrixConfig::test(),
|
||||
policy: PolicyConfig::test(),
|
||||
hack: HackConfig::test(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,10 @@ use opentelemetry::{
|
||||
use rand::SeedableRng;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{passwords::PasswordManager, upstream_oauth2::cache::MetadataCache, MatrixHomeserver};
|
||||
use crate::{
|
||||
passwords::PasswordManager, site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
|
||||
MatrixHomeserver,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
@ -50,6 +53,7 @@ pub struct AppState {
|
||||
pub http_client_factory: HttpClientFactory,
|
||||
pub password_manager: PasswordManager,
|
||||
pub metadata_cache: MetadataCache,
|
||||
pub site_config: SiteConfig,
|
||||
pub conn_acquisition_histogram: Option<Histogram<u64>>,
|
||||
}
|
||||
|
||||
@ -199,6 +203,12 @@ impl FromRef<AppState> for MetadataCache {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<AppState> for SiteConfig {
|
||||
fn from_ref(input: &AppState) -> Self {
|
||||
input.site_config.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FromRequestParts<AppState> for BoxClock {
|
||||
type Rejection = Infallible;
|
||||
|
@ -32,7 +32,7 @@ use thiserror::Error;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use super::{MatrixError, MatrixHomeserver};
|
||||
use crate::{impl_from_error_for_route, passwords::PasswordManager};
|
||||
use crate::{impl_from_error_for_route, passwords::PasswordManager, site_config::SiteConfig};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
@ -210,6 +210,7 @@ pub(crate) async fn post(
|
||||
State(password_manager): State<PasswordManager>,
|
||||
mut repo: BoxRepository,
|
||||
State(homeserver): State<MatrixHomeserver>,
|
||||
State(site_config): State<SiteConfig>,
|
||||
Json(input): Json<RequestBody>,
|
||||
) -> Result<impl IntoResponse, RouteError> {
|
||||
let (session, user) = match (password_manager.is_enabled(), input.credentials) {
|
||||
@ -242,8 +243,7 @@ pub(crate) async fn post(
|
||||
|
||||
// If the client asked for a refreshable token, make it expire
|
||||
let expires_in = if input.refresh_token {
|
||||
// TODO: this should be configurable
|
||||
Some(Duration::minutes(5))
|
||||
Some(site_config.compat_token_ttl)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use axum::{response::IntoResponse, Json};
|
||||
use axum::{extract::State, response::IntoResponse, Json};
|
||||
use chrono::Duration;
|
||||
use hyper::StatusCode;
|
||||
use mas_data_model::{TokenFormatError, TokenType};
|
||||
@ -25,7 +25,7 @@ use serde_with::{serde_as, DurationMilliSeconds};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::MatrixError;
|
||||
use crate::impl_from_error_for_route;
|
||||
use crate::{impl_from_error_for_route, site_config::SiteConfig};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RequestBody {
|
||||
@ -91,6 +91,7 @@ pub(crate) async fn post(
|
||||
mut rng: BoxRng,
|
||||
clock: BoxClock,
|
||||
mut repo: BoxRepository,
|
||||
State(site_config): State<SiteConfig>,
|
||||
Json(input): Json<RequestBody>,
|
||||
) -> Result<impl IntoResponse, RouteError> {
|
||||
let token_type = TokenType::check(&input.refresh_token)?;
|
||||
@ -128,7 +129,7 @@ pub(crate) async fn post(
|
||||
let new_refresh_token_str = TokenType::CompatRefreshToken.generate(&mut rng);
|
||||
let new_access_token_str = TokenType::CompatAccessToken.generate(&mut rng);
|
||||
|
||||
let expires_in = Duration::minutes(5);
|
||||
let expires_in = site_config.compat_token_ttl;
|
||||
let new_access_token = repo
|
||||
.compat_access_token()
|
||||
.add(
|
||||
|
@ -68,6 +68,7 @@ pub mod passwords;
|
||||
pub mod upstream_oauth2;
|
||||
mod views;
|
||||
|
||||
mod site_config;
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
@ -89,8 +90,10 @@ macro_rules! impl_from_error_for_route {
|
||||
|
||||
pub use mas_axum_utils::{cookies::CookieManager, http_client_factory::HttpClientFactory};
|
||||
|
||||
pub use self::{app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema};
|
||||
pub use crate::upstream_oauth2::cache::MetadataCache;
|
||||
pub use self::{
|
||||
app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema,
|
||||
site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
|
||||
};
|
||||
|
||||
pub fn healthcheck_router<S, B>() -> Router<S, B>
|
||||
where
|
||||
@ -169,6 +172,7 @@ where
|
||||
BoxRepository: FromRequestParts<S>,
|
||||
Encrypter: FromRef<S>,
|
||||
HttpClientFactory: FromRef<S>,
|
||||
SiteConfig: FromRef<S>,
|
||||
BoxClock: FromRequestParts<S>,
|
||||
BoxRng: FromRequestParts<S>,
|
||||
Policy: FromRequestParts<S>,
|
||||
@ -225,9 +229,10 @@ where
|
||||
<B as HttpBody>::Error: std::error::Error + Send + Sync,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
UrlBuilder: FromRef<S>,
|
||||
BoxRepository: FromRequestParts<S>,
|
||||
SiteConfig: FromRef<S>,
|
||||
MatrixHomeserver: FromRef<S>,
|
||||
PasswordManager: FromRef<S>,
|
||||
BoxRepository: FromRequestParts<S>,
|
||||
BoxClock: FromRequestParts<S>,
|
||||
BoxRng: FromRequestParts<S>,
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ use tracing::debug;
|
||||
use url::Url;
|
||||
|
||||
use super::{generate_id_token, generate_token_pair};
|
||||
use crate::impl_from_error_for_route;
|
||||
use crate::{impl_from_error_for_route, site_config::SiteConfig};
|
||||
|
||||
#[serde_as]
|
||||
#[skip_serializing_none]
|
||||
@ -161,6 +161,7 @@ pub(crate) async fn post(
|
||||
State(key_store): State<Keystore>,
|
||||
State(url_builder): State<UrlBuilder>,
|
||||
mut repo: BoxRepository,
|
||||
State(site_config): State<SiteConfig>,
|
||||
State(encrypter): State<Encrypter>,
|
||||
client_authorization: ClientAuthorization<AccessTokenRequest>,
|
||||
) -> Result<impl IntoResponse, RouteError> {
|
||||
@ -191,12 +192,13 @@ pub(crate) async fn post(
|
||||
&client,
|
||||
&key_store,
|
||||
&url_builder,
|
||||
&site_config,
|
||||
repo,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
AccessTokenRequest::RefreshToken(grant) => {
|
||||
refresh_token_grant(&mut rng, &clock, &grant, &client, repo).await?
|
||||
refresh_token_grant(&mut rng, &clock, &grant, &client, &site_config, repo).await?
|
||||
}
|
||||
_ => {
|
||||
return Err(RouteError::UnsupportedGrantType);
|
||||
@ -220,6 +222,7 @@ async fn authorization_code_grant(
|
||||
client: &Client,
|
||||
key_store: &Keystore,
|
||||
url_builder: &UrlBuilder,
|
||||
site_config: &SiteConfig,
|
||||
mut repo: BoxRepository,
|
||||
) -> Result<(AccessTokenResponse, BoxRepository), RouteError> {
|
||||
let authz_grant = repo
|
||||
@ -312,7 +315,7 @@ async fn authorization_code_grant(
|
||||
.get_last_authentication(&browser_session)
|
||||
.await?;
|
||||
|
||||
let ttl = Duration::minutes(5);
|
||||
let ttl = site_config.access_token_ttl;
|
||||
let (access_token, refresh_token) =
|
||||
generate_token_pair(&mut rng, clock, &mut repo, &session, ttl).await?;
|
||||
|
||||
@ -367,6 +370,7 @@ async fn refresh_token_grant(
|
||||
clock: &impl Clock,
|
||||
grant: &RefreshTokenGrant,
|
||||
client: &Client,
|
||||
site_config: &SiteConfig,
|
||||
mut repo: BoxRepository,
|
||||
) -> Result<(AccessTokenResponse, BoxRepository), RouteError> {
|
||||
let refresh_token = repo
|
||||
@ -390,7 +394,7 @@ async fn refresh_token_grant(
|
||||
return Err(RouteError::InvalidGrant);
|
||||
}
|
||||
|
||||
let ttl = Duration::minutes(5);
|
||||
let ttl = site_config.access_token_ttl;
|
||||
let (new_access_token, new_refresh_token) =
|
||||
generate_token_pair(rng, clock, &mut repo, &session, ttl).await?;
|
||||
|
||||
|
31
crates/handlers/src/site_config.rs
Normal file
31
crates/handlers/src/site_config.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use chrono::Duration;
|
||||
|
||||
/// Random site configuration we don't now where to put yet.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SiteConfig {
|
||||
pub access_token_ttl: Duration,
|
||||
pub compat_token_ttl: Duration,
|
||||
}
|
||||
|
||||
impl Default for SiteConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
access_token_ttl: Duration::minutes(5),
|
||||
compat_token_ttl: Duration::minutes(5),
|
||||
}
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ use url::Url;
|
||||
use crate::{
|
||||
app_state::ErrorWrapper,
|
||||
passwords::{Hasher, PasswordManager},
|
||||
site_config::SiteConfig,
|
||||
upstream_oauth2::cache::MetadataCache,
|
||||
MatrixHomeserver,
|
||||
};
|
||||
@ -76,6 +77,7 @@ pub(crate) struct TestState {
|
||||
pub graphql_schema: mas_graphql::Schema,
|
||||
pub http_client_factory: HttpClientFactory,
|
||||
pub password_manager: PasswordManager,
|
||||
pub site_config: SiteConfig,
|
||||
pub clock: Arc<MockClock>,
|
||||
pub rng: Arc<Mutex<ChaChaRng>>,
|
||||
}
|
||||
@ -133,6 +135,8 @@ impl TestState {
|
||||
|
||||
let http_client_factory = HttpClientFactory::new(10);
|
||||
|
||||
let site_config = SiteConfig::default();
|
||||
|
||||
let clock = Arc::new(MockClock::default());
|
||||
let rng = Arc::new(Mutex::new(ChaChaRng::seed_from_u64(42)));
|
||||
|
||||
@ -160,6 +164,7 @@ impl TestState {
|
||||
graphql_schema,
|
||||
http_client_factory,
|
||||
password_manager,
|
||||
site_config,
|
||||
clock,
|
||||
rng,
|
||||
})
|
||||
@ -346,6 +351,12 @@ impl FromRef<TestState> for MetadataCache {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<TestState> for SiteConfig {
|
||||
fn from_ref(input: &TestState) -> Self {
|
||||
input.site_config.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FromRequestParts<TestState> for BoxClock {
|
||||
type Rejection = Infallible;
|
||||
|
@ -16,17 +16,6 @@
|
||||
"$ref": "#/definitions/ClientConfig"
|
||||
}
|
||||
},
|
||||
"csrf": {
|
||||
"description": "Configuration related to Cross-Site Request Forgery protections",
|
||||
"default": {
|
||||
"ttl": 3600
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CsrfConfig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"database": {
|
||||
"description": "Database connection configuration",
|
||||
"default": {
|
||||
@ -56,6 +45,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"hack": {
|
||||
"description": "Miscellaneous configuration options",
|
||||
"default": {
|
||||
"access_token_ttl": 300,
|
||||
"compat_token_ttl": 300
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HackConfig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"http": {
|
||||
"description": "Configuration of the HTTP server",
|
||||
"default": {
|
||||
@ -464,20 +465,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CsrfConfig": {
|
||||
"description": "Configuration related to Cross-Site Request Forgery protections",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ttl": {
|
||||
"description": "Time-to-live of a CSRF token in seconds",
|
||||
"default": 3600,
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"maximum": 86400.0,
|
||||
"minimum": 60.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"DatabaseConfig": {
|
||||
"description": "Database connection configuration",
|
||||
"type": "object",
|
||||
@ -737,6 +724,28 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"HackConfig": {
|
||||
"description": "Configuration sections for miscellaneous options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_token_ttl": {
|
||||
"description": "Time-to-live of access tokens in seconds",
|
||||
"default": 300,
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"maximum": 86400.0,
|
||||
"minimum": 60.0
|
||||
},
|
||||
"compat_token_ttl": {
|
||||
"description": "Time-to-live of compatibility access tokens in seconds",
|
||||
"default": 300,
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"maximum": 86400.0,
|
||||
"minimum": 60.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"HashingScheme": {
|
||||
"description": "A hashing algorithm",
|
||||
"type": "object",
|
||||
|
Reference in New Issue
Block a user