loco_oauth2/config.rs
1use crate::error::OAuth2StoreError;
2use crate::grants::authorization_code::{CookieConfig, Credentials, UrlConfig};
3use serde::de::Error;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::str::FromStr;
7
8/// `OAuth2 Authentication configuration`
9/// # Fields
10/// * `secret_key` - Optional, key for Private Cookie Jar, must be more than 64 bytes. If not provided, a new key will be generated.
11/// * `authorization_code` - Authorization code grant type
12///
13/// Example (development):
14/// ```yaml
15/// # config/development.yaml
16/// oauth2:
17/// secret_key: {{get_env(name="OAUTH_PRIVATE_KEY", default="144, 76, 183, 1, 15, 184, 233, 174, 214, 251, 190, 186, 122, 61, 74, 84, 225, 110, 189, 115, 10, 251, 133, 128, 52, 46, 15, 66, 85, 1, 245, 73, 27, 113, 189, 15, 209, 205, 61, 100, 73, 31, 18, 58, 235, 105, 141, 36, 70, 92, 231, 151, 27, 32, 243, 117, 30, 244, 110, 89, 233, 196, 137, 130")}} # Optional, key for Private Cookie Jar, must be more than 64 bytes. If not provided, a new key will be generated.
18/// authorization_code: # Authorization code grant type
19/// - client_identifier: google # Identifier for the OAuth2 provider. Replace 'google' with your provider's name if different, must be unique within the oauth2 config.
20/// client_credentials:
21/// client_id: <your client id> # Replace with your OAuth2 client ID.
22/// client_secret: <your client secret> # Replace with your OAuth2 client secret.
23/// url_config:
24/// auth_url: https://accounts.google.com/o/oauth2/auth # authorization endpoint from the provider
25/// token_url: https://www.googleapis.com/oauth2/v3/token # token endpoint from the provider for exchanging the authorization code for an access token
26/// redirect_url: http://localhost:5150/api/auth/google_callback # server callback endpoint for the provider
27/// profile_url: https://openidconnect.googleapis.com/v1/userinfo # user profile endpoint from the provider for getting user data
28/// scopes:
29/// - https://www.googleapis.com/auth/userinfo.email # Scopes for requesting access to user data
30/// cookie_config:
31/// protected_url: http://localhost:5150/api/auth/google_callback # Optional - For redirecting to protect url in cookie to prevent XSS attack
32/// timeout_seconds: 600 # Optional, default 600 seconds
33/// ```
34#[derive(Debug, Clone, Deserialize, Serialize)]
35pub struct Config {
36 pub secret_key: Option<Vec<u8>>,
37 pub authorization_code: Vec<AuthorizationCode>,
38}
39
40#[derive(Debug, Clone, Deserialize, Serialize)]
41pub struct AuthorizationCode {
42 pub client_identifier: String,
43 pub client_credentials: Credentials,
44 pub url_config: UrlConfig,
45 pub cookie_config: CookieConfig,
46 pub timeout_seconds: Option<u64>,
47}
48
49impl TryFrom<Value> for Config {
50 type Error = OAuth2StoreError;
51 #[tracing::instrument(name = "Convert Value to OAuth2Config")]
52 fn try_from(value: Value) -> Result<Self, Self::Error> {
53 let secret_key: Option<Vec<u8>> =
54 value.get("secret_key").and_then(|v| v.as_str()).map(|s| {
55 s.split(", ")
56 .filter_map(|byte| u8::from_str(byte.trim()).ok())
57 .collect()
58 });
59
60 let authorization_code: Vec<AuthorizationCode> = value
61 .get("authorization_code")
62 .and_then(|v| v.as_array())
63 .ok_or_else(|| {
64 serde_json::Error::custom("authorization_code is not an array or is missing")
65 })
66 .and_then(|v| {
67 v.iter()
68 .map(|item| serde_json::from_value(item.clone()))
69 .collect()
70 })?;
71 Ok(Self {
72 secret_key,
73 authorization_code,
74 })
75 }
76}