Skip to main content

authx_core/models/
oidc.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5// ── OAuth2 / OIDC Client ───────────────────────────────────────────────────────
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct OidcClient {
9    pub id: Uuid,
10    pub client_id: String,
11    /// SHA-256 hash of the client secret (like a password — never stored raw).
12    pub secret_hash: String,
13    pub name: String,
14    pub redirect_uris: Vec<String>,
15    /// Allowed OAuth2 grant types (e.g. "authorization_code", "refresh_token").
16    pub grant_types: Vec<String>,
17    /// Allowed response types (e.g. "code").
18    pub response_types: Vec<String>,
19    /// Space-separated allowed scopes (e.g. "openid profile email").
20    pub allowed_scopes: String,
21    pub created_at: DateTime<Utc>,
22}
23
24#[derive(Debug, Clone)]
25pub struct CreateOidcClient {
26    pub name: String,
27    pub redirect_uris: Vec<String>,
28    pub grant_types: Vec<String>,
29    pub response_types: Vec<String>,
30    pub allowed_scopes: String,
31    /// SHA-256 hash of the client secret (empty for public clients).
32    pub secret_hash: String,
33}
34
35// ── Authorization Code ────────────────────────────────────────────────────────
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct AuthorizationCode {
39    pub id: Uuid,
40    pub code_hash: String,
41    pub client_id: String,
42    pub user_id: Uuid,
43    pub redirect_uri: String,
44    pub scope: String,
45    pub nonce: Option<String>,
46    /// PKCE S256 code challenge (optional but recommended).
47    pub code_challenge: Option<String>,
48    pub expires_at: DateTime<Utc>,
49    pub used: bool,
50}
51
52#[derive(Debug, Clone)]
53pub struct CreateAuthorizationCode {
54    pub code_hash: String,
55    pub client_id: String,
56    pub user_id: Uuid,
57    pub redirect_uri: String,
58    pub scope: String,
59    pub nonce: Option<String>,
60    pub code_challenge: Option<String>,
61    pub expires_at: DateTime<Utc>,
62}
63
64// ── Access / Refresh Tokens ───────────────────────────────────────────────────
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct OidcToken {
68    pub id: Uuid,
69    pub token_hash: String,
70    pub client_id: String,
71    pub user_id: Uuid,
72    pub scope: String,
73    pub token_type: OidcTokenType,
74    pub expires_at: Option<DateTime<Utc>>,
75    pub revoked: bool,
76    pub created_at: DateTime<Utc>,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80#[serde(rename_all = "snake_case")]
81pub enum OidcTokenType {
82    Access,
83    Refresh,
84    DeviceAccess,
85}
86
87#[derive(Debug, Clone)]
88pub struct CreateOidcToken {
89    pub token_hash: String,
90    pub client_id: String,
91    pub user_id: Uuid,
92    pub scope: String,
93    pub token_type: OidcTokenType,
94    pub expires_at: Option<DateTime<Utc>>,
95}
96
97// ── Device Authorization ──────────────────────────────────────────────────────
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct DeviceCode {
101    pub id: Uuid,
102    /// SHA-256 of the device_code sent to the device.
103    pub device_code_hash: String,
104    /// SHA-256 of the user_code shown on the device.
105    pub user_code_hash: String,
106    /// The raw user_code (short, human-typeable — e.g. "BDWD-HQPK").
107    pub user_code: String,
108    pub client_id: String,
109    pub scope: String,
110    pub expires_at: DateTime<Utc>,
111    pub interval_secs: u32,
112    pub authorized: bool,
113    pub denied: bool,
114    pub user_id: Option<Uuid>,
115    pub last_polled_at: Option<DateTime<Utc>>,
116}
117
118#[derive(Debug, Clone)]
119pub struct CreateDeviceCode {
120    pub device_code_hash: String,
121    pub user_code_hash: String,
122    pub user_code: String,
123    pub client_id: String,
124    pub scope: String,
125    pub expires_at: DateTime<Utc>,
126    pub interval_secs: u32,
127}
128
129// ── SSO / OIDC Federation ─────────────────────────────────────────────────────
130
131/// An external OIDC IdP configuration (e.g. corporate Okta, Azure AD).
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct OidcFederationProvider {
134    pub id: Uuid,
135    pub name: String,
136    /// The OIDC issuer URL (used to discover .well-known/openid-configuration).
137    pub issuer: String,
138    pub client_id: String,
139    /// AES-GCM encrypted client secret.
140    pub secret_enc: String,
141    pub scopes: String,
142    /// Optional organization this provider is scoped to.
143    pub org_id: Option<Uuid>,
144    pub enabled: bool,
145    pub created_at: DateTime<Utc>,
146    /// Claim mapping rules (JSON array). Empty means no mapping.
147    #[serde(default)]
148    pub claim_mapping: Vec<ClaimMappingRule>,
149}
150
151/// A rule that maps an external IdP claim to a local attribute or role.
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct ClaimMappingRule {
154    /// The external claim path (e.g. "groups", "email", "roles").
155    pub source_claim: String,
156    /// Match condition: "equals", "contains", "regex".
157    pub match_type: String,
158    /// Value to match against.
159    pub match_value: String,
160    /// Action: "assign_role", "set_attribute", "add_to_org".
161    pub action: String,
162    /// Target value for the action (e.g. role name, attribute value, org slug).
163    pub target: String,
164}
165
166#[derive(Debug, Clone)]
167pub struct CreateOidcFederationProvider {
168    pub name: String,
169    pub issuer: String,
170    pub client_id: String,
171    pub secret_enc: String,
172    pub scopes: String,
173    pub org_id: Option<Uuid>,
174    pub claim_mapping: Vec<ClaimMappingRule>,
175}