commit aa1be322bd6184be11df33dd0f293c0f90ed31dd
parent 2eaed97d77e4f1341daaadf4cfe3e66935b84e0e
Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt>
Date: Mon, 8 Dec 2025 20:20:18 +0100
oauth2_gateway: fix scope in /authorize
Diffstat:
6 files changed, 21 insertions(+), 44 deletions(-)
diff --git a/oauth2_gateway/oauth2_gatewaydb/oauth2gw-0001.sql b/oauth2_gateway/oauth2_gatewaydb/oauth2gw-0001.sql
@@ -16,7 +16,6 @@ CREATE TABLE IF NOT EXISTS clients (
webhook_url TEXT NOT NULL,
verifier_url TEXT NOT NULL,
verifier_management_api_path VARCHAR(255) DEFAULT '/management/api/verifications',
- scope TEXT NOT NULL DEFAULT 'age_over_18',
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
@@ -32,8 +31,6 @@ COMMENT ON COLUMN clients.verifier_url
IS 'Client URL where oauth2 gateway will callback';
COMMENT ON COLUMN clients.verifier_management_api_path
IS 'Swiyu verifier api endpoint to create verification requests';
-COMMENT ON COLUMN clients.scope
- IS 'Space-delimited OAuth2 scope (requested verification attributes, e.g., "first_name last_name age_over_18")';
CREATE INDEX IF NOT EXISTS idx_clients_client_id ON clients(client_id);
diff --git a/oauth2_gateway/src/bin/client_management_cli.rs b/oauth2_gateway/src/bin/client_management_cli.rs
@@ -54,10 +54,6 @@ enum Commands {
/// Verifier management API path (default: /management/api/verifications)
#[arg(long)]
verifier_api_path: Option<String>,
-
- /// OAuth2 scope (space-delimited attributes, default: "age_over_18")
- #[arg(long)]
- scope: Option<String>,
},
Update {
@@ -71,9 +67,6 @@ enum Commands {
#[arg(long)]
verifier_api_path: Option<String>,
-
- #[arg(long)]
- scope: Option<String>,
},
/// Delete a client (WARNING: cascades to all sessions)
@@ -108,7 +101,6 @@ async fn main() -> Result<()> {
webhook_url,
verifier_url,
verifier_api_path,
- scope,
} => {
cmd_create_client(
&pool,
@@ -117,7 +109,6 @@ async fn main() -> Result<()> {
&webhook_url,
&verifier_url,
verifier_api_path.as_deref(),
- scope.as_deref(),
)
.await?
}
@@ -126,7 +117,6 @@ async fn main() -> Result<()> {
webhook_url,
verifier_url,
verifier_api_path,
- scope,
} => {
cmd_update_client(
&pool,
@@ -134,7 +124,6 @@ async fn main() -> Result<()> {
webhook_url.as_deref(),
verifier_url.as_deref(),
verifier_api_path.as_deref(),
- scope.as_deref(),
)
.await?
}
@@ -181,7 +170,6 @@ async fn cmd_show_client(pool: &sqlx::PgPool, client_id: &str) -> Result<()> {
println!("Webhook URL: {}", client.webhook_url);
println!("Verifier URL: {}", client.verifier_url);
println!("Verifier API Path: {}", client.verifier_management_api_path);
- println!("Scope: {}", client.scope);
println!("Created: {}", client.created_at);
println!("Updated: {}", client.updated_at);
@@ -195,7 +183,6 @@ async fn cmd_create_client(
webhook_url: &str,
verifier_url: &str,
verifier_api_path: Option<&str>,
- scope: Option<&str>,
) -> Result<()> {
let client = db::clients::register_client(
pool,
@@ -204,7 +191,6 @@ async fn cmd_create_client(
webhook_url,
verifier_url,
verifier_api_path,
- scope,
)
.await
.context("Failed to create client")?;
@@ -214,7 +200,6 @@ async fn cmd_create_client(
println!("UUID: {}", client.id);
println!("Client ID: {}", client.client_id);
println!("Webhook URL: {}", client.webhook_url);
- println!("Scope: {}", client.scope);
Ok(())
}
@@ -225,10 +210,9 @@ async fn cmd_update_client(
webhook_url: Option<&str>,
verifier_url: Option<&str>,
verifier_api_path: Option<&str>,
- scope: Option<&str>,
) -> Result<()> {
- if webhook_url.is_none() && verifier_url.is_none() && verifier_api_path.is_none() && scope.is_none() {
- anyhow::bail!("No fields to update. Specify at least one of: --webhook-url, --verifier-url, --verifier-api-path, --scope");
+ if webhook_url.is_none() && verifier_url.is_none() && verifier_api_path.is_none() {
+ anyhow::bail!("No fields to update. Specify at least one of: --webhook-url, --verifier-url, --verifier-api-path");
}
let client = db::clients::get_client_by_id(pool, client_id)
@@ -241,7 +225,6 @@ async fn cmd_update_client(
webhook_url,
verifier_url,
verifier_api_path,
- scope,
)
.await
.context("Failed to update client")?;
@@ -253,7 +236,6 @@ async fn cmd_update_client(
println!("Webhook URL: {}", updated.webhook_url);
println!("Verifier URL: {}", updated.verifier_url);
println!("Verifier API Path: {}", updated.verifier_management_api_path);
- println!("Scope: {}", updated.scope);
Ok(())
}
diff --git a/oauth2_gateway/src/db/clients.rs b/oauth2_gateway/src/db/clients.rs
@@ -14,7 +14,6 @@ pub struct Client {
pub webhook_url: String,
pub verifier_url: String,
pub verifier_management_api_path: String,
- pub scope: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
@@ -27,21 +26,19 @@ pub async fn register_client(
webhook_url: &str,
verifier_url: &str,
verifier_management_api_path: Option<&str>,
- scope: Option<&str>,
) -> Result<Client> {
let api_path = verifier_management_api_path
.unwrap_or("/management/api/verifications");
- let scope_value = scope.unwrap_or("age_over_18");
let secret_hash = bcrypt::hash(client_secret, bcrypt::DEFAULT_COST)?;
let client = sqlx::query_as::<_, Client>(
r#"
INSERT INTO oauth2gw.clients
- (client_id, secret_hash, webhook_url, verifier_url, verifier_management_api_path, scope)
- VALUES ($1, $2, $3, $4, $5, $6)
+ (client_id, secret_hash, webhook_url, verifier_url, verifier_management_api_path)
+ VALUES ($1, $2, $3, $4, $5)
RETURNING id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
"#
)
.bind(client_id)
@@ -49,7 +46,6 @@ pub async fn register_client(
.bind(webhook_url)
.bind(verifier_url)
.bind(api_path)
- .bind(scope_value)
.fetch_one(pool)
.await?;
@@ -64,7 +60,7 @@ pub async fn get_client_by_id(
let client = sqlx::query_as::<_, Client>(
r#"
SELECT id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
FROM oauth2gw.clients
WHERE client_id = $1
"#
@@ -84,7 +80,7 @@ pub async fn get_client_by_uuid(
let client = sqlx::query_as::<_, Client>(
r#"
SELECT id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
FROM oauth2gw.clients
WHERE id = $1
"#
@@ -128,7 +124,7 @@ pub async fn authenticate_client(
let client = sqlx::query_as::<_, Client>(
r#"
SELECT id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
FROM oauth2gw.clients
WHERE client_id = $1
"#
@@ -156,7 +152,6 @@ pub async fn update_client(
webhook_url: Option<&str>,
verifier_url: Option<&str>,
verifier_management_api_path: Option<&str>,
- scope: Option<&str>,
) -> Result<Client> {
let current = get_client_by_uuid(pool, id).await?
.ok_or_else(|| anyhow::anyhow!("Client not found"))?;
@@ -165,7 +160,6 @@ pub async fn update_client(
let new_verifier_url = verifier_url.unwrap_or(¤t.verifier_url);
let new_verifier_api_path = verifier_management_api_path
.unwrap_or(¤t.verifier_management_api_path);
- let new_scope = scope.unwrap_or(¤t.scope);
let client = sqlx::query_as::<_, Client>(
r#"
@@ -174,17 +168,15 @@ pub async fn update_client(
webhook_url = $1,
verifier_url = $2,
verifier_management_api_path = $3,
- scope = $4,
updated_at = CURRENT_TIMESTAMP
- WHERE id = $5
+ WHERE id = $4
RETURNING id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
"#
)
.bind(new_webhook_url)
.bind(new_verifier_url)
.bind(new_verifier_api_path)
- .bind(new_scope)
.bind(id)
.fetch_one(pool)
.await?;
@@ -217,7 +209,7 @@ pub async fn list_clients(pool: &PgPool) -> Result<Vec<Client>> {
let clients = sqlx::query_as::<_, Client>(
r#"
SELECT id, client_id, secret_hash, webhook_url, verifier_url,
- verifier_management_api_path, scope, created_at, updated_at
+ verifier_management_api_path, created_at, updated_at
FROM oauth2gw.clients
ORDER BY created_at DESC
"#
diff --git a/oauth2_gateway/src/db/sessions.rs b/oauth2_gateway/src/db/sessions.rs
@@ -89,7 +89,7 @@ pub async fn create_session(
r#"
INSERT INTO oauth2gw.verification_sessions (client_id, nonce, scope,
expires_at, status)
- SELECT c.id, $1, c.scope, NOW() + $2 * INTERVAL '1 minute', 'pending'
+ SELECT c.id, $1, '', NOW() + $2 * INTERVAL '1 minute', 'pending'
FROM oauth2gw.clients c
WHERE c.client_id = $3
RETURNING
@@ -110,17 +110,19 @@ pub async fn create_session(
/// Fetch session and client data for /authorize endpoint
///
/// Returns all data needed for backend validation and idempotent responses.
+/// Updates the session scope with the provided scope parameter.
///
/// Used by the /authorize endpoint
pub async fn get_session_for_authorize(
pool: &PgPool,
nonce: &str,
client_id: &str,
+ scope: &str,
) -> Result<Option<AuthorizeSessionData>> {
let result = sqlx::query(
r#"
UPDATE oauth2gw.verification_sessions s
- SET status = s.status
+ SET scope = $3
FROM oauth2gw.clients c
WHERE s.client_id = c.id
AND s.nonce = $1
@@ -140,6 +142,7 @@ pub async fn get_session_for_authorize(
)
.bind(nonce)
.bind(client_id)
+ .bind(scope)
.fetch_optional(pool)
.await?;
diff --git a/oauth2_gateway/src/handlers.rs b/oauth2_gateway/src/handlers.rs
@@ -123,11 +123,12 @@ pub async fn authorize(
Query(params): Query<AuthorizeQuery>,
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
tracing::info!(
- "Authorize request for client: {}, nonce: {}, state: {}, redirect_uri: {}",
+ "Authorize request for client: {}, nonce: {}, state: {}, redirect_uri: {}, scope: {}",
params.client_id,
nonce,
params.state,
- params.redirect_uri
+ params.redirect_uri,
+ params.scope
);
if params.response_type != "code" {
@@ -141,6 +142,7 @@ pub async fn authorize(
&state.pool,
&nonce,
¶ms.client_id,
+ ¶ms.scope,
)
.await
.map_err(|e| {
diff --git a/oauth2_gateway/src/models.rs b/oauth2_gateway/src/models.rs
@@ -13,6 +13,7 @@ pub struct AuthorizeQuery {
pub client_id: String,
pub redirect_uri: String,
pub state: String,
+ pub scope: String,
}
#[derive(Debug, Deserialize, Serialize)]