1use std::time::Duration;
2
3use tonic::codegen::async_trait;
4
5use crate::api::RuntimeMetadata;
6use crate::error::{Error, Result};
7
8#[derive(Clone, Debug, Default, PartialEq, Eq)]
10pub struct AuthenticatedUser {
11 pub subject: String,
13 pub email: String,
15 pub email_verified: bool,
17 pub display_name: String,
19 pub avatar_url: String,
21 pub claims: std::collections::BTreeMap<String, String>,
23}
24
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
27pub struct BeginLoginRequest {
28 pub callback_url: String,
30 pub host_state: String,
32 pub scopes: Vec<String>,
34 pub options: std::collections::BTreeMap<String, String>,
36}
37
38#[derive(Clone, Debug, Default, PartialEq, Eq)]
40pub struct BeginLoginResponse {
41 pub authorization_url: String,
43 pub provider_state: Vec<u8>,
45}
46
47#[derive(Clone, Debug, Default, PartialEq, Eq)]
49pub struct CompleteLoginRequest {
50 pub query: std::collections::BTreeMap<String, String>,
52 pub provider_state: Vec<u8>,
54 pub callback_url: String,
56}
57
58#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
60pub struct AuthSessionSettings {
61 pub session_ttl: Duration,
63}
64
65pub(crate) fn begin_login_request_from_proto(
66 value: crate::generated::v1::BeginLoginRequest,
67) -> BeginLoginRequest {
68 BeginLoginRequest {
69 callback_url: value.callback_url,
70 host_state: value.host_state,
71 scopes: value.scopes,
72 options: value.options,
73 }
74}
75
76pub(crate) fn begin_login_response_to_proto(
77 value: BeginLoginResponse,
78) -> crate::generated::v1::BeginLoginResponse {
79 crate::generated::v1::BeginLoginResponse {
80 authorization_url: value.authorization_url,
81 provider_state: value.provider_state,
82 }
83}
84
85pub(crate) fn complete_login_request_from_proto(
86 value: crate::generated::v1::CompleteLoginRequest,
87) -> CompleteLoginRequest {
88 CompleteLoginRequest {
89 query: value.query,
90 provider_state: value.provider_state,
91 callback_url: value.callback_url,
92 }
93}
94
95pub(crate) fn authenticated_user_to_proto(
96 value: AuthenticatedUser,
97) -> crate::generated::v1::AuthenticatedUser {
98 crate::generated::v1::AuthenticatedUser {
99 subject: value.subject,
100 email: value.email,
101 email_verified: value.email_verified,
102 display_name: value.display_name,
103 avatar_url: value.avatar_url,
104 claims: value.claims,
105 }
106}
107
108pub(crate) fn auth_session_settings_to_proto(
109 value: AuthSessionSettings,
110) -> crate::generated::v1::AuthSessionSettings {
111 crate::generated::v1::AuthSessionSettings {
112 session_ttl_seconds: i64::try_from(value.session_ttl.as_secs()).unwrap_or(i64::MAX),
113 }
114}
115
116#[async_trait]
117pub trait AuthenticationProvider: Send + Sync + 'static {
119 async fn configure(
121 &self,
122 _name: &str,
123 _config: serde_json::Map<String, serde_json::Value>,
124 ) -> Result<()> {
125 Ok(())
126 }
127
128 fn metadata(&self) -> Option<RuntimeMetadata> {
130 None
131 }
132
133 fn warnings(&self) -> Vec<String> {
135 Vec::new()
136 }
137
138 async fn health_check(&self) -> Result<()> {
140 Ok(())
141 }
142
143 async fn start(&self) -> Result<()> {
145 Ok(())
146 }
147
148 async fn close(&self) -> Result<()> {
150 Ok(())
151 }
152
153 async fn begin_login(&self, req: BeginLoginRequest) -> Result<BeginLoginResponse>;
155
156 async fn complete_login(&self, req: CompleteLoginRequest) -> Result<AuthenticatedUser>;
158
159 async fn validate_external_token(&self, _token: &str) -> Result<Option<AuthenticatedUser>> {
161 Err(Error::unimplemented(
162 "authentication provider does not support external token validation",
163 ))
164 }
165
166 fn session_settings(&self) -> Option<AuthSessionSettings> {
168 None
169 }
170
171 fn session_ttl(&self) -> Option<Duration> {
175 None
176 }
177}