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
Implement the client credentials grant
This commit is contained in:
@ -218,7 +218,7 @@ async fn get_requester(
|
||||
};
|
||||
|
||||
// If there is a user for this session, check that it is not locked
|
||||
let user_valid = user.as_ref().map_or(false, User::is_valid);
|
||||
let user_valid = user.as_ref().map_or(true, User::is_valid);
|
||||
|
||||
if !token.is_valid(clock.now()) || !session.is_valid() || !user_valid {
|
||||
return Err(RouteError::InvalidToken);
|
||||
|
@ -16,8 +16,13 @@ use axum::http::Request;
|
||||
use chrono::Duration;
|
||||
use hyper::StatusCode;
|
||||
use mas_data_model::{AccessToken, Client, TokenType, User};
|
||||
use mas_router::SimpleRoute;
|
||||
use mas_storage::{oauth2::OAuth2ClientRepository, RepositoryAccess};
|
||||
use oauth2_types::scope::{Scope, ScopeToken, OPENID};
|
||||
use oauth2_types::{
|
||||
registration::ClientRegistrationResponse,
|
||||
requests::AccessTokenResponse,
|
||||
scope::{Scope, ScopeToken, OPENID},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::test_utils::{init_tracing, RequestBuilderExt, ResponseExt, TestState};
|
||||
@ -349,3 +354,106 @@ async fn test_oauth2_admin(pool: PgPool) {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that we can query the GraphQL endpoint with a token from a
|
||||
/// client_credentials grant.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_oauth2_client_credentials(pool: PgPool) {
|
||||
init_tracing();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
// Provision a client
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2RegistrationEndpoint::PATH).json(serde_json::json!({
|
||||
"client_uri": "https://example.com/",
|
||||
// XXX: we shouldn't have to specify the redirect URI here, but the policy denies it for now
|
||||
"redirect_uris": ["https://example.com/callback"],
|
||||
"contacts": ["contact@example.com"],
|
||||
"token_endpoint_auth_method": "client_secret_post",
|
||||
"grant_types": ["client_credentials"],
|
||||
"response_types": [],
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::CREATED);
|
||||
|
||||
let response: ClientRegistrationResponse = response.json();
|
||||
let client_id = response.client_id;
|
||||
let client_secret = response.client_secret.expect("to have a client secret");
|
||||
|
||||
// Call the token endpoint with an empty scope
|
||||
let request = Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"scope": "urn:mas:graphql:*",
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let AccessTokenResponse { access_token, .. } = response.json();
|
||||
|
||||
let request = Request::post("/graphql")
|
||||
.bearer(&access_token)
|
||||
.json(serde_json::json!({
|
||||
"query": r#"
|
||||
query {
|
||||
viewer {
|
||||
__typename
|
||||
}
|
||||
|
||||
viewerSession {
|
||||
__typename
|
||||
}
|
||||
}
|
||||
"#,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let response: GraphQLResponse = response.json();
|
||||
assert!(response.errors.is_empty());
|
||||
assert_eq!(
|
||||
response.data,
|
||||
serde_json::json!({
|
||||
"viewer": {
|
||||
// There is no user associated with the client credentials grant
|
||||
"__typename": "Anonymous",
|
||||
},
|
||||
"viewerSession": {
|
||||
// But there is a session
|
||||
"__typename": "Oauth2Session",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Check that we can't do a query once the token is revoked
|
||||
let request = Request::post(mas_router::OAuth2Revocation::PATH).form(serde_json::json!({
|
||||
"token": access_token,
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
// Do the same request again
|
||||
let request = Request::post("/graphql")
|
||||
.bearer(&access_token)
|
||||
.json(serde_json::json!({
|
||||
"query": r#"
|
||||
query {
|
||||
viewer {
|
||||
__typename
|
||||
}
|
||||
|
||||
viewerSession {
|
||||
__typename
|
||||
}
|
||||
}
|
||||
"#,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -20,8 +20,10 @@ use mas_axum_utils::{
|
||||
client_authorization::{ClientAuthorization, CredentialsVerificationError},
|
||||
http_client_factory::HttpClientFactory,
|
||||
};
|
||||
use mas_data_model::{AuthorizationGrantStage, Client, Device};
|
||||
use mas_data_model::{AuthorizationGrantStage, Client, Device, TokenType};
|
||||
use mas_keystore::{Encrypter, Keystore};
|
||||
use mas_oidc_client::types::scope::ScopeToken;
|
||||
use mas_policy::Policy;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::{
|
||||
job::{JobRepositoryExt, ProvisionDeviceJob},
|
||||
@ -36,7 +38,8 @@ use oauth2_types::{
|
||||
errors::{ClientError, ClientErrorCode},
|
||||
pkce::CodeChallengeError,
|
||||
requests::{
|
||||
AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, RefreshTokenGrant,
|
||||
AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, ClientCredentialsGrant,
|
||||
GrantType, RefreshTokenGrant,
|
||||
},
|
||||
scope,
|
||||
};
|
||||
@ -92,6 +95,9 @@ pub(crate) enum RouteError {
|
||||
#[error("invalid grant")]
|
||||
InvalidGrant,
|
||||
|
||||
#[error("policy denied the request")]
|
||||
DeniedByPolicy(Vec<mas_policy::Violation>),
|
||||
|
||||
#[error("unsupported grant type")]
|
||||
UnsupportedGrantType,
|
||||
|
||||
@ -132,6 +138,18 @@ impl IntoResponse for RouteError {
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Json(ClientError::from(ClientErrorCode::UnauthorizedClient)),
|
||||
),
|
||||
Self::DeniedByPolicy(violations) => (
|
||||
StatusCode::FORBIDDEN,
|
||||
Json(
|
||||
ClientError::from(ClientErrorCode::InvalidScope).with_description(
|
||||
violations
|
||||
.into_iter()
|
||||
.map(|violation| violation.msg)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
),
|
||||
),
|
||||
),
|
||||
Self::InvalidGrant | Self::GrantNotFound => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
Json(ClientError::from(ClientErrorCode::InvalidGrant)),
|
||||
@ -146,6 +164,7 @@ impl IntoResponse for RouteError {
|
||||
}
|
||||
|
||||
impl_from_error_for_route!(mas_storage::RepositoryError);
|
||||
impl_from_error_for_route!(mas_policy::EvaluationError);
|
||||
impl_from_error_for_route!(super::IdTokenSignatureError);
|
||||
|
||||
#[tracing::instrument(
|
||||
@ -163,6 +182,7 @@ pub(crate) async fn post(
|
||||
mut repo: BoxRepository,
|
||||
State(site_config): State<SiteConfig>,
|
||||
State(encrypter): State<Encrypter>,
|
||||
policy: Policy,
|
||||
client_authorization: ClientAuthorization<AccessTokenRequest>,
|
||||
) -> Result<impl IntoResponse, RouteError> {
|
||||
let client = client_authorization
|
||||
@ -200,6 +220,18 @@ pub(crate) async fn post(
|
||||
AccessTokenRequest::RefreshToken(grant) => {
|
||||
refresh_token_grant(&mut rng, &clock, &grant, &client, &site_config, repo).await?
|
||||
}
|
||||
AccessTokenRequest::ClientCredentials(grant) => {
|
||||
client_credentials_grant(
|
||||
&mut rng,
|
||||
&clock,
|
||||
&grant,
|
||||
&client,
|
||||
&site_config,
|
||||
repo,
|
||||
policy,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
_ => {
|
||||
return Err(RouteError::UnsupportedGrantType);
|
||||
}
|
||||
@ -420,6 +452,58 @@ async fn refresh_token_grant(
|
||||
Ok((params, repo))
|
||||
}
|
||||
|
||||
async fn client_credentials_grant(
|
||||
rng: &mut BoxRng,
|
||||
clock: &impl Clock,
|
||||
grant: &ClientCredentialsGrant,
|
||||
client: &Client,
|
||||
site_config: &SiteConfig,
|
||||
mut repo: BoxRepository,
|
||||
mut policy: Policy,
|
||||
) -> Result<(AccessTokenResponse, BoxRepository), RouteError> {
|
||||
// Check that the client is allowed to use this grant type
|
||||
if !client.grant_types.contains(&GrantType::ClientCredentials) {
|
||||
return Err(RouteError::UnauthorizedClient);
|
||||
}
|
||||
|
||||
// Default to an empty scope if none is provided
|
||||
let scope = grant
|
||||
.scope
|
||||
.clone()
|
||||
.unwrap_or_else(|| std::iter::empty::<ScopeToken>().collect());
|
||||
|
||||
// Make the request go through the policy engine
|
||||
let res = policy
|
||||
.evaluate_client_credentials_grant(&scope, client)
|
||||
.await?;
|
||||
if !res.valid() {
|
||||
return Err(RouteError::DeniedByPolicy(res.violations));
|
||||
}
|
||||
|
||||
// Start the session
|
||||
let session = repo
|
||||
.oauth2_session()
|
||||
.add_from_client_credentials(rng, clock, client, scope)
|
||||
.await?;
|
||||
|
||||
let ttl = site_config.access_token_ttl;
|
||||
let access_token_str = TokenType::AccessToken.generate(rng);
|
||||
|
||||
let access_token = repo
|
||||
.oauth2_access_token()
|
||||
.add(rng, clock, &session, access_token_str, ttl)
|
||||
.await?;
|
||||
|
||||
let mut params = AccessTokenResponse::new(access_token.access_token).with_expires_in(ttl);
|
||||
|
||||
if !session.scope.is_empty() {
|
||||
// We only return the scope if it's not empty
|
||||
params = params.with_scope(session.scope);
|
||||
}
|
||||
|
||||
Ok((params, repo))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hyper::Request;
|
||||
@ -767,7 +851,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_unsupported_grant(pool: PgPool) {
|
||||
async fn test_client_credentials(pool: PgPool) {
|
||||
init_tracing();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
@ -775,6 +859,7 @@ mod tests {
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2RegistrationEndpoint::PATH).json(serde_json::json!({
|
||||
"client_uri": "https://example.com/",
|
||||
// XXX: we shouldn't have to specify the redirect URI here, but the policy denies it for now
|
||||
"redirect_uris": ["https://example.com/callback"],
|
||||
"contacts": ["contact@example.com"],
|
||||
"token_endpoint_auth_method": "client_secret_post",
|
||||
@ -789,7 +874,7 @@ mod tests {
|
||||
let client_id = response.client_id;
|
||||
let client_secret = response.client_secret.expect("to have a client secret");
|
||||
|
||||
// Call the token endpoint with an unsupported grant type
|
||||
// Call the token endpoint with an empty scope
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "client_credentials",
|
||||
@ -797,6 +882,137 @@ mod tests {
|
||||
"client_secret": client_secret,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
let response: AccessTokenResponse = response.json();
|
||||
assert!(response.refresh_token.is_none());
|
||||
assert!(response.expires_in.is_some());
|
||||
assert!(response.scope.is_none());
|
||||
|
||||
// Revoke the token
|
||||
let request = Request::post(mas_router::OAuth2Revocation::PATH).form(serde_json::json!({
|
||||
"token": response.access_token,
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
// We should be allowed to ask for the GraphQL API scope
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"scope": "urn:mas:graphql:*"
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
let response: AccessTokenResponse = response.json();
|
||||
assert!(response.refresh_token.is_none());
|
||||
assert!(response.expires_in.is_some());
|
||||
assert_eq!(response.scope, Some("urn:mas:graphql:*".parse().unwrap()));
|
||||
|
||||
// Revoke the token
|
||||
let request = Request::post(mas_router::OAuth2Revocation::PATH).form(serde_json::json!({
|
||||
"token": response.access_token,
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
// We should be NOT allowed to ask for the MAS admin scope
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"scope": "urn:mas:admin"
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::FORBIDDEN);
|
||||
|
||||
let ClientError { error, .. } = response.json();
|
||||
assert_eq!(error, ClientErrorCode::InvalidScope);
|
||||
|
||||
// Now, if we add the client to the admin list in the policy, it should work
|
||||
let state = {
|
||||
let mut state = state;
|
||||
state.policy_factory = crate::test_utils::policy_factory(serde_json::json!({
|
||||
"admin_clients": [client_id]
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
state
|
||||
};
|
||||
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"scope": "urn:mas:admin"
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
|
||||
let response: AccessTokenResponse = response.json();
|
||||
assert!(response.refresh_token.is_none());
|
||||
assert!(response.expires_in.is_some());
|
||||
assert_eq!(response.scope, Some("urn:mas:admin".parse().unwrap()));
|
||||
|
||||
// Revoke the token
|
||||
let request = Request::post(mas_router::OAuth2Revocation::PATH).form(serde_json::json!({
|
||||
"token": response.access_token,
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_unsupported_grant(pool: PgPool) {
|
||||
init_tracing();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
// Provision a client
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2RegistrationEndpoint::PATH).json(serde_json::json!({
|
||||
"client_uri": "https://example.com/",
|
||||
"redirect_uris": ["https://example.com/callback"],
|
||||
"contacts": ["contact@example.com"],
|
||||
"token_endpoint_auth_method": "client_secret_post",
|
||||
"grant_types": ["password"],
|
||||
"response_types": [],
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::CREATED);
|
||||
|
||||
let response: ClientRegistrationResponse = response.json();
|
||||
let client_id = response.client_id;
|
||||
let client_secret = response.client_secret.expect("to have a client secret");
|
||||
|
||||
// Call the token endpoint with an unsupported grant type
|
||||
let request =
|
||||
Request::post(mas_router::OAuth2TokenEndpoint::PATH).form(serde_json::json!({
|
||||
"grant_type": "password",
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"username": "john",
|
||||
"password": "hunter2",
|
||||
}));
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::BAD_REQUEST);
|
||||
let ClientError { error, .. } = response.json();
|
||||
|
@ -63,6 +63,28 @@ pub(crate) fn init_tracing() {
|
||||
.try_init();
|
||||
}
|
||||
|
||||
pub(crate) async fn policy_factory(
|
||||
data: serde_json::Value,
|
||||
) -> Result<Arc<PolicyFactory>, anyhow::Error> {
|
||||
let workspace_root = camino::Utf8Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("..");
|
||||
|
||||
let file = tokio::fs::File::open(workspace_root.join("policies").join("policy.wasm")).await?;
|
||||
|
||||
let entrypoints = mas_policy::Entrypoints {
|
||||
register: "register/violation".to_owned(),
|
||||
client_registration: "client_registration/violation".to_owned(),
|
||||
authorization_grant: "authorization_grant/violation".to_owned(),
|
||||
email: "email/violation".to_owned(),
|
||||
password: "password/violation".to_owned(),
|
||||
};
|
||||
|
||||
let policy_factory = PolicyFactory::load(file, data, entrypoints).await?;
|
||||
let policy_factory = Arc::new(policy_factory);
|
||||
Ok(policy_factory)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestState {
|
||||
pub pool: PgPool,
|
||||
@ -116,23 +138,10 @@ impl TestState {
|
||||
|
||||
let homeserver = MatrixHomeserver::new("example.com".to_owned());
|
||||
|
||||
let file =
|
||||
tokio::fs::File::open(workspace_root.join("policies").join("policy.wasm")).await?;
|
||||
|
||||
let entrypoints = mas_policy::Entrypoints {
|
||||
register: "register/violation".to_owned(),
|
||||
client_registration: "client_registration/violation".to_owned(),
|
||||
authorization_grant: "authorization_grant/violation".to_owned(),
|
||||
email: "email/violation".to_owned(),
|
||||
password: "password/violation".to_owned(),
|
||||
};
|
||||
|
||||
let policy_factory = PolicyFactory::load(file, serde_json::json!({}), entrypoints).await?;
|
||||
let policy_factory = policy_factory(serde_json::json!({})).await?;
|
||||
|
||||
let homeserver_connection = MockHomeserverConnection::new("example.com");
|
||||
|
||||
let policy_factory = Arc::new(policy_factory);
|
||||
|
||||
let http_client_factory = HttpClientFactory::new(10);
|
||||
|
||||
let site_config = SiteConfig::default();
|
||||
|
@ -574,7 +574,7 @@ pub enum AccessTokenRequest {
|
||||
DeviceCode(DeviceCodeGrant),
|
||||
|
||||
/// An unsupported request.
|
||||
#[serde(skip, other)]
|
||||
#[serde(skip_serializing, other)]
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
|
@ -314,7 +314,7 @@ impl Policy {
|
||||
user: &User,
|
||||
) -> Result<EvaluationResult, EvaluationError> {
|
||||
let input = AuthorizationGrantInput {
|
||||
user,
|
||||
user: Some(user),
|
||||
client,
|
||||
scope: &authorization_grant.scope,
|
||||
grant_type: GrantType::AuthorizationCode,
|
||||
@ -338,7 +338,6 @@ impl Policy {
|
||||
fields(
|
||||
input.scope = %scope,
|
||||
input.client.id = %client.id,
|
||||
input.user.id = %user.id,
|
||||
),
|
||||
err,
|
||||
)]
|
||||
@ -346,10 +345,9 @@ impl Policy {
|
||||
&mut self,
|
||||
scope: &Scope,
|
||||
client: &Client,
|
||||
user: &User,
|
||||
) -> Result<EvaluationResult, EvaluationError> {
|
||||
let input = AuthorizationGrantInput {
|
||||
user,
|
||||
user: None,
|
||||
client,
|
||||
scope,
|
||||
grant_type: GrantType::ClientCredentials,
|
||||
|
@ -107,9 +107,9 @@ pub enum GrantType {
|
||||
pub struct AuthorizationGrantInput<'a> {
|
||||
#[cfg_attr(
|
||||
feature = "jsonschema",
|
||||
schemars(with = "std::collections::HashMap<String, serde_json::Value>")
|
||||
schemars(with = "Option<std::collections::HashMap<String, serde_json::Value>>")
|
||||
)]
|
||||
pub user: &'a User,
|
||||
pub user: Option<&'a User>,
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "jsonschema",
|
||||
|
22
crates/storage-pg/.sqlx/query-2e1d7fb3f69d99dc5c879f43d92bc52f9abeb606393aff5440f948632d914708.json
generated
Normal file
22
crates/storage-pg/.sqlx/query-2e1d7fb3f69d99dc5c879f43d92bc52f9abeb606393aff5440f948632d914708.json
generated
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , grant_type_client_credentials\n , token_endpoint_auth_method\n , jwks\n , jwks_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, TRUE)\n ON CONFLICT (oauth2_client_id)\n DO\n UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret\n , grant_type_authorization_code = EXCLUDED.grant_type_authorization_code\n , grant_type_refresh_token = EXCLUDED.grant_type_refresh_token\n , grant_type_client_credentials = EXCLUDED.grant_type_client_credentials\n , token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method\n , jwks = EXCLUDED.jwks\n , jwks_uri = EXCLUDED.jwks_uri\n , is_static = TRUE\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"TextArray",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2e1d7fb3f69d99dc5c879f43d92bc52f9abeb606393aff5440f948632d914708"
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, FALSE)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"Text",
|
||||
"TextArray",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "34fbe0f0485a9c4060399509f087964c454252b9b111a57c9106cfc3fdc71b8a"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = ANY($1::uuid[])\n ",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , grant_type_client_credentials\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = ANY($1::uuid[])\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -35,66 +35,71 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "grant_type_client_credentials",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "contacts",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "client_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "logo_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "client_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 11,
|
||||
"name": "policy_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 12,
|
||||
"name": "tos_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 13,
|
||||
"name": "jwks_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 14,
|
||||
"name": "jwks",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 15,
|
||||
"name": "id_token_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 16,
|
||||
"name": "userinfo_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 17,
|
||||
"name": "token_endpoint_auth_method",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 18,
|
||||
"name": "token_endpoint_auth_signing_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 19,
|
||||
"name": "initiate_login_uri",
|
||||
"type_info": "Text"
|
||||
}
|
||||
@ -112,6 +117,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@ -126,5 +132,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "35734c4b54d2f1b2c311806af3e9a592f5f55f4898c6e39eb0d7c1b9cef7ca63"
|
||||
"hash": "59a7b0eb03e45db5bee0aa1447fef2a3c061cf385ccf67acb237b94a0f25a074"
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , token_endpoint_auth_method\n , jwks\n , jwks_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, TRUE)\n ON CONFLICT (oauth2_client_id)\n DO\n UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret\n , grant_type_authorization_code = EXCLUDED.grant_type_authorization_code\n , grant_type_refresh_token = EXCLUDED.grant_type_refresh_token\n , token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method\n , jwks = EXCLUDED.jwks\n , jwks_uri = EXCLUDED.jwks_uri\n , is_static = TRUE\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"TextArray",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "73ea17a71d62bf96f7811b7f57802f5065f0ae831bc8f3c66b5be4a47b37467e"
|
||||
}
|
32
crates/storage-pg/.sqlx/query-8cd9e33fb146fd528dbb169b6339d33703b6b719d5f28f1cf232bc81cac0da85.json
generated
Normal file
32
crates/storage-pg/.sqlx/query-8cd9e33fb146fd528dbb169b6339d33703b6b719d5f28f1cf232bc81cac0da85.json
generated
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , grant_type_client_credentials\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, FALSE)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"Text",
|
||||
"TextArray",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8cd9e33fb146fd528dbb169b6339d33703b6b719d5f28f1cf232bc81cac0da85"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = $1\n ",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , grant_type_client_credentials\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -35,66 +35,71 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "grant_type_client_credentials",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "contacts",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "client_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "logo_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "client_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 11,
|
||||
"name": "policy_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 12,
|
||||
"name": "tos_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 13,
|
||||
"name": "jwks_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 14,
|
||||
"name": "jwks",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 15,
|
||||
"name": "id_token_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 16,
|
||||
"name": "userinfo_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 17,
|
||||
"name": "token_endpoint_auth_method",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 18,
|
||||
"name": "token_endpoint_auth_signing_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 19,
|
||||
"name": "initiate_login_uri",
|
||||
"type_info": "Text"
|
||||
}
|
||||
@ -112,6 +117,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@ -126,5 +132,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "e6250ea5c861cd7568999fd8f490daf1407b1b3619e3a05c70b5fe9ccf9aa7b5"
|
||||
"hash": "9697ae6915c7e9268c82a4a2bf7a538515bb2be35c003f49e93641fb1d5ed8af"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n WHERE is_static = TRUE\n ",
|
||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , grant_type_client_credentials\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n WHERE is_static = TRUE\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -35,66 +35,71 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "grant_type_client_credentials",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "contacts",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "client_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "logo_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "client_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 11,
|
||||
"name": "policy_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 12,
|
||||
"name": "tos_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 13,
|
||||
"name": "jwks_uri",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 14,
|
||||
"name": "jwks",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 15,
|
||||
"name": "id_token_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 16,
|
||||
"name": "userinfo_signed_response_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 17,
|
||||
"name": "token_endpoint_auth_method",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 18,
|
||||
"name": "token_endpoint_auth_signing_alg",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 19,
|
||||
"name": "initiate_login_uri",
|
||||
"type_info": "Text"
|
||||
}
|
||||
@ -110,6 +115,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@ -124,5 +130,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b2b71d12c3a4a7436bbe961c6c57e17a5c5e4105d01184a38d12607d853df802"
|
||||
"hash": "ef45f7ed060951ec7d881f2da2a9454eb32c4620cac1ea13c7186df513692fd6"
|
||||
}
|
@ -13,4 +13,9 @@
|
||||
-- limitations under the License.
|
||||
|
||||
-- This makes the user_id in the oauth2_sessions nullable, which allows us to create user-less sessions
|
||||
ALTER TABLE oauth2_sessions ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE oauth2_sessions
|
||||
ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
||||
-- This adds a column to the oauth2_clients to allow them to use the client_credentials flow
|
||||
ALTER TABLE oauth2_clients
|
||||
ADD COLUMN grant_type_client_credentials boolean NOT NULL DEFAULT false;
|
@ -63,6 +63,7 @@ struct OAuth2ClientLookup {
|
||||
// response_types: Vec<String>,
|
||||
grant_type_authorization_code: bool,
|
||||
grant_type_refresh_token: bool,
|
||||
grant_type_client_credentials: bool,
|
||||
contacts: Vec<String>,
|
||||
client_name: Option<String>,
|
||||
logo_uri: Option<String>,
|
||||
@ -126,6 +127,9 @@ impl TryInto<Client> for OAuth2ClientLookup {
|
||||
if self.grant_type_refresh_token {
|
||||
grant_types.push(GrantType::RefreshToken);
|
||||
}
|
||||
if self.grant_type_client_credentials {
|
||||
grant_types.push(GrantType::ClientCredentials);
|
||||
}
|
||||
|
||||
let logo_uri = self.logo_uri.map(|s| s.parse()).transpose().map_err(|e| {
|
||||
DatabaseInconsistencyError::on("oauth2_clients")
|
||||
@ -293,6 +297,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, redirect_uris
|
||||
, grant_type_authorization_code
|
||||
, grant_type_refresh_token
|
||||
, grant_type_client_credentials
|
||||
, contacts
|
||||
, client_name
|
||||
, logo_uri
|
||||
@ -343,6 +348,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, redirect_uris
|
||||
, grant_type_authorization_code
|
||||
, grant_type_refresh_token
|
||||
, grant_type_client_credentials
|
||||
, contacts
|
||||
, client_name
|
||||
, logo_uri
|
||||
@ -429,6 +435,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, redirect_uris
|
||||
, grant_type_authorization_code
|
||||
, grant_type_refresh_token
|
||||
, grant_type_client_credentials
|
||||
, client_name
|
||||
, logo_uri
|
||||
, client_uri
|
||||
@ -444,7 +451,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, is_static
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, FALSE)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, FALSE)
|
||||
"#,
|
||||
Uuid::from(id),
|
||||
encrypted_client_secret,
|
||||
@ -452,6 +459,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
&redirect_uris_array,
|
||||
grant_types.contains(&GrantType::AuthorizationCode),
|
||||
grant_types.contains(&GrantType::RefreshToken),
|
||||
grant_types.contains(&GrantType::ClientCredentials),
|
||||
client_name,
|
||||
logo_uri.as_ref().map(Url::as_str),
|
||||
client_uri.as_ref().map(Url::as_str),
|
||||
@ -544,18 +552,20 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, redirect_uris
|
||||
, grant_type_authorization_code
|
||||
, grant_type_refresh_token
|
||||
, grant_type_client_credentials
|
||||
, token_endpoint_auth_method
|
||||
, jwks
|
||||
, jwks_uri
|
||||
, is_static
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, TRUE)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, TRUE)
|
||||
ON CONFLICT (oauth2_client_id)
|
||||
DO
|
||||
UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret
|
||||
, grant_type_authorization_code = EXCLUDED.grant_type_authorization_code
|
||||
, grant_type_refresh_token = EXCLUDED.grant_type_refresh_token
|
||||
, grant_type_client_credentials = EXCLUDED.grant_type_client_credentials
|
||||
, token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method
|
||||
, jwks = EXCLUDED.jwks
|
||||
, jwks_uri = EXCLUDED.jwks_uri
|
||||
@ -566,6 +576,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
&redirect_uris_array,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
client_auth_method,
|
||||
jwks_json,
|
||||
jwks_uri.as_ref().map(Url::as_str),
|
||||
@ -592,7 +603,11 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
OAuthAuthorizationEndpointResponseType::IdToken,
|
||||
OAuthAuthorizationEndpointResponseType::None,
|
||||
],
|
||||
grant_types: Vec::new(),
|
||||
grant_types: vec![
|
||||
GrantType::AuthorizationCode,
|
||||
GrantType::RefreshToken,
|
||||
GrantType::ClientCredentials,
|
||||
],
|
||||
contacts: Vec::new(),
|
||||
client_name: None,
|
||||
logo_uri: None,
|
||||
@ -626,6 +641,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
||||
, redirect_uris
|
||||
, grant_type_authorization_code
|
||||
, grant_type_refresh_token
|
||||
, grant_type_client_credentials
|
||||
, contacts
|
||||
, client_name
|
||||
, logo_uri
|
||||
|
Reference in New Issue
Block a user