alibi_plugins/oauth_provider/
initial_access_token.rs1use alibi_core::endpoint::{EndpointError, is_endpoint_api_error};
3use alibi_core::{AuthError, Headers};
4use async_trait::async_trait;
5use serde_json::{Map, Value};
6
7#[derive(Debug)]
9pub struct OAuthInitialAccessTokenInput<'a> {
10 pub initial_access_token: &'a str,
11 pub headers: &'a Headers,
12 pub client_metadata: &'a Map<String, Value>,
14}
15
16#[derive(Debug, Clone, Default)]
18pub struct OAuthInitialAccessTokenAuthorization {
19 pub reference_id: Option<String>,
20}
21
22#[derive(Debug)]
25pub enum OAuthInitialAccessTokenError {
26 Endpoint(EndpointError),
27 Application(AuthError),
28}
29
30impl From<EndpointError> for OAuthInitialAccessTokenError {
31 fn from(error: EndpointError) -> Self {
32 Self::Endpoint(error)
33 }
34}
35
36impl From<AuthError> for OAuthInitialAccessTokenError {
37 fn from(error: AuthError) -> Self {
38 if is_endpoint_api_error(&error) {
39 Self::Endpoint(error.into())
40 } else {
41 Self::Application(error)
42 }
43 }
44}
45
46impl std::fmt::Display for OAuthInitialAccessTokenError {
47 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match self {
49 Self::Endpoint(error) => error.fmt(formatter),
50 Self::Application(error) => error.fmt(formatter),
51 }
52 }
53}
54
55impl std::error::Error for OAuthInitialAccessTokenError {
56 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
57 Some(match self {
58 Self::Endpoint(error) => error,
59 Self::Application(error) => error,
60 })
61 }
62}
63
64#[async_trait]
66pub trait OAuthInitialAccessTokenValidator: Send + Sync + std::fmt::Debug {
67 async fn validate(
68 &self,
69 input: OAuthInitialAccessTokenInput<'_>,
70 ) -> Result<Option<OAuthInitialAccessTokenAuthorization>, OAuthInitialAccessTokenError>;
71}
72
73impl super::OAuthProviderPlugin {
74 pub(super) async fn authorize_initial_access_token(
75 &self,
76 input: OAuthInitialAccessTokenInput<'_>,
77 ) -> alibi_core::AuthResult<
78 Result<OAuthInitialAccessTokenAuthorization, alibi_core::endpoint::EndpointResponse>,
79 > {
80 use alibi_core::endpoint::EndpointResponse;
81
82 let validation = match &self.config.initial_access_token_validator {
83 Some(validator) => validator.validate(input).await,
84 None => Ok(None),
85 };
86 let response = match validation {
87 Ok(Some(authorization)) => return Ok(Ok(authorization)),
88 Ok(None) => super::clients::status_protocol_error(
89 401,
90 "invalid_token",
91 "Invalid initial access token",
92 )?
93 .with_header("WWW-Authenticate", "Bearer error=\"invalid_token\""),
94 Err(OAuthInitialAccessTokenError::Application(_)) => {
95 super::clients::status_protocol_error(
96 500,
97 "server_error",
98 "Initial access token validation failed",
99 )?
100 }
101 Err(OAuthInitialAccessTokenError::Endpoint(error)) => {
102 let mut response = EndpointResponse::error(error.error);
103 if let Some(body) = error.body {
104 response = response.with_error_body(*body);
105 }
106 if error.body_absent {
107 response = response.without_error_body();
108 }
109 if let Some(headers) = error.headers {
110 response.merge_headers(headers);
111 }
112 response
113 }
114 };
115 Ok(Err(response))
116 }
117}