Skip to main content

headless_lms_server/controllers/main_frontend/oauth/
authorized_clients.rs

1use crate::domain::exercise_services::token::invalidate_cached_users;
2use crate::prelude::*;
3use actix_web::{HttpResponse, web};
4use headless_lms_base::config::ApplicationConfiguration;
5use headless_lms_utils::cache::Cache;
6use models::oauth_user_client_scopes::{AuthorizedClientInfo, OAuthUserClientScopes};
7use sqlx::PgPool;
8use utoipa::OpenApi;
9use uuid::Uuid;
10
11#[derive(OpenApi)]
12#[openapi(paths(get_authorized_clients, delete_authorized_client))]
13#[allow(dead_code)]
14pub(crate) struct MainFrontendOauthAuthorizedClientsApiDoc;
15
16#[instrument(skip(pool, auth_user))]
17#[utoipa::path(
18    get,
19    path = "/authorized-clients",
20    operation_id = "getOauthAuthorizedClients",
21    tag = "oauth",
22    responses(
23        (status = 200, description = "Authorized OAuth clients", body = [AuthorizedClientInfo])
24    )
25)]
26pub async fn get_authorized_clients(
27    pool: web::Data<PgPool>,
28    auth_user: AuthUser,
29) -> ControllerResult<HttpResponse> {
30    let mut conn = pool.acquire().await?;
31    let token = skip_authorize();
32
33    let rows: Vec<AuthorizedClientInfo> =
34        OAuthUserClientScopes::list_authorized_clients_for_user(&mut conn, auth_user.id).await?;
35
36    token.authorized_ok(HttpResponse::Ok().json(rows))
37}
38
39#[instrument(skip(pool, auth_user, app_conf, cache))]
40#[utoipa::path(
41    delete,
42    path = "/authorized-clients/{client_id}",
43    operation_id = "deleteOauthAuthorizedClient",
44    tag = "oauth",
45    params(
46        ("client_id" = Uuid, Path, description = "OAuth client id")
47    ),
48    responses(
49        (status = 204, description = "Authorized client revoked")
50    )
51)]
52pub async fn delete_authorized_client(
53    pool: web::Data<PgPool>,
54    auth_user: AuthUser,
55    path: web::Path<Uuid>, // client_id (DB uuid)
56    app_conf: web::Data<ApplicationConfiguration>,
57    cache: web::Data<Cache>,
58) -> ControllerResult<HttpResponse> {
59    let client_id = path.into_inner();
60    let mut conn = pool.acquire().await?;
61    let token = skip_authorize();
62
63    let revoked_digests =
64        OAuthUserClientScopes::revoke_user_client_everything(&mut conn, auth_user.id, client_id)
65            .await?;
66
67    // Without this the deleted tokens keep authenticating from cache for the rest of their TTL.
68    let token_hmac_key = &app_conf.oauth_server_configuration.oauth_token_hmac_key;
69    invalidate_cached_users(&cache, &revoked_digests, token_hmac_key).await;
70
71    token.authorized_ok(HttpResponse::NoContent().finish())
72}
73
74pub fn _add_routes(cfg: &mut web::ServiceConfig) {
75    cfg.route("/authorized-clients", web::get().to(get_authorized_clients))
76        .route(
77            "/authorized-clients/{client_id}",
78            web::delete().to(delete_authorized_client),
79        );
80}