Skip to main content

openauth_plugins/api_key/routes/
delete.rs

1use http::{Method, StatusCode};
2use serde::{Deserialize, Serialize};
3
4use super::{
5    body, config_id_matches, current_identity, endpoint, error, json, SharedConfigurations,
6};
7use crate::api_key::errors;
8use crate::api_key::options::ApiKeyReference;
9use crate::api_key::organization::{ensure_organization_permission, owns_user_key, ApiKeyAction};
10use crate::api_key::storage::ApiKeyStore;
11
12#[derive(Debug, Clone, Deserialize, Serialize, Default)]
13#[serde(rename_all = "camelCase")]
14pub struct DeleteApiKeyRequest {
15    pub key_id: String,
16    pub config_id: Option<String>,
17}
18
19#[derive(Debug, Clone, Serialize)]
20struct DeleteApiKeyResponse {
21    success: bool,
22}
23
24pub fn delete_endpoint(
25    configurations: SharedConfigurations,
26) -> openauth_core::api::AsyncAuthEndpoint {
27    endpoint(
28        "/api-key/delete",
29        Method::POST,
30        configurations,
31        |context, request, configurations| {
32            Box::pin(async move {
33                let input: DeleteApiKeyRequest = body(&request)?;
34                let options = configurations.resolve(input.config_id.as_deref())?;
35                let Some(identity) = current_identity(context, &request).await? else {
36                    return error(StatusCode::UNAUTHORIZED, errors::UNAUTHORIZED_SESSION);
37                };
38                let store = ApiKeyStore::new(context, &options);
39                let Some(api_key) = store.get_by_id(&input.key_id).await? else {
40                    return error(StatusCode::NOT_FOUND, errors::KEY_NOT_FOUND);
41                };
42                let expected_config_id = options.config_id.as_deref().unwrap_or("default");
43                if !config_id_matches(&api_key.config_id, expected_config_id) {
44                    return error(StatusCode::NOT_FOUND, errors::KEY_NOT_FOUND);
45                }
46                match options.reference {
47                    ApiKeyReference::User
48                        if owns_user_key(
49                            options.reference,
50                            &api_key.reference_id,
51                            &identity.user.id,
52                        ) => {}
53                    ApiKeyReference::User => {
54                        return error(StatusCode::NOT_FOUND, errors::KEY_NOT_FOUND)
55                    }
56                    ApiKeyReference::Organization => {
57                        if let Err(error) = ensure_organization_permission(
58                            context,
59                            &identity.user.id,
60                            &api_key.reference_id,
61                            ApiKeyAction::Delete,
62                        )
63                        .await
64                        {
65                            return error_response_from_openauth(error);
66                        }
67                    }
68                }
69                store.delete(&api_key).await?;
70                json(StatusCode::OK, &DeleteApiKeyResponse { success: true })
71            })
72        },
73    )
74}
75
76fn error_response_from_openauth(
77    error: openauth_core::error::OpenAuthError,
78) -> Result<openauth_core::api::ApiResponse, openauth_core::error::OpenAuthError> {
79    let message = error.to_string();
80    if message.contains(errors::message(errors::USER_NOT_MEMBER_OF_ORGANIZATION)) {
81        return super::error(
82            StatusCode::FORBIDDEN,
83            errors::USER_NOT_MEMBER_OF_ORGANIZATION,
84        );
85    }
86    if message.contains(errors::message(errors::ORGANIZATION_PLUGIN_REQUIRED)) {
87        return super::error(
88            StatusCode::INTERNAL_SERVER_ERROR,
89            errors::ORGANIZATION_PLUGIN_REQUIRED,
90        );
91    }
92    super::error(
93        StatusCode::FORBIDDEN,
94        errors::INSUFFICIENT_API_KEY_PERMISSIONS,
95    )
96}