1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//! User credential types and verification abstractions.
//!
//! This module provides the [`Credentials`] type for handling user login data
//! and the [`CredentialsVerifier`] trait for validating credentials against
//! stored authentication secrets.
//!
//! # Quick Start
//!
//! ```rust
//! use axum_gate::prelude::Credentials;
//!
//! // Create credentials from user input
//! let credentials = Credentials::new(&"user@example.com".to_string(), "password123");
//!
//! // Use with JSON APIs
//! use serde_json;
//! let json = r#"{"id": "admin@company.com", "secret": "admin_pass"}"#;
//! let creds: Credentials<String> = serde_json::from_str(json)?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! # Security Considerations
//!
//! **⚠️ Important Security Notes:**
//!
//! - **Contains plaintext secrets** - Handle credentials with extreme care
//! - **Never log credentials** - They contain sensitive password data
//! - **Minimize lifetime** - Process and discard credentials quickly
//! - **Use HTTPS/TLS** - Always encrypt credentials during transmission
//! - **Timing attack protection** - Built-in when using axum-gate login services
//!
//! # Integration with Authentication
//!
//! Credentials integrate seamlessly with axum-gate's authentication system:
//!
//! ```rust
//! use axum::{Json, extract::State, http::StatusCode};
//! use axum_gate::prelude::Credentials;
//! use axum_gate::route_handlers::login;
//! use axum_extra::extract::CookieJar;
//!
//! async fn login_endpoint(
//! cookie_jar: CookieJar,
//! Json(credentials): Json<Credentials<String>>,
//! // State with repositories and JWT codec...
//! ) -> Result<CookieJar, StatusCode> {
//! // Use the pre-built login handler
//! // login(cookie_jar, credentials, claims, secret_repo, account_repo, codec, template).await
//! # Ok(cookie_jar)
//! }
//! ```
pub use CredentialsVerifier;
use ;
/// Authentication credentials containing a user identifier and plaintext secret.
///
/// This type represents user login data as typically received from client applications,
/// containing a user identifier (such as email, username, or user ID) paired with a
/// plaintext secret (password). Credentials are used during the authentication process
/// to verify user identity against stored account data.
///
/// # Generic Parameter
///
/// - `Id`: The type of user identifier (commonly [`String`] for emails/usernames, or [`uuid::Uuid`] for user IDs)
///
/// # Security Considerations
///
/// **⚠️ Critical Security Notes:**
///
/// - **Plaintext secrets**: This type contains unencrypted passwords - handle with extreme care
/// - **Memory safety**: Minimize the lifetime of credential instances in memory
/// - **Logging**: Never log or print credential values - they contain sensitive data
/// - **Transport security**: Always use HTTPS/TLS when transmitting credentials
/// - **Storage**: Never store credentials directly - convert to hashed secrets for persistence
///
/// # Authentication Flow Integration
///
/// Credentials are typically used as input to authentication services:
///
/// ```rust
/// use axum_gate::prelude::Credentials;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// // 1. Receive credentials from client (e.g., JSON payload)
/// let client_credentials = Credentials::new(&"user@example.com".to_string(), "user_password");
///
/// // 2. Use in authentication service
/// // The login service will:
/// // - Look up the user account
/// // - Retrieve the stored secret hash
/// // - Verify the plaintext password against the hash
/// // - Return authentication result
/// # Ok(())
/// # }
/// ```
///
/// # Timing Attack Protection
///
/// When used with the built-in [`login`](crate::route_handlers::login) handler or [`LoginService`](crate::authn::LoginService),
/// credentials are processed using constant-time operations to prevent timing-based
/// user enumeration attacks:
///
/// - Authentication takes consistent time regardless of whether the user exists
/// - Password verification always occurs, even for non-existent users
/// - Error responses don't distinguish between "user not found" and "wrong password"
///
/// # JSON Serialization
///
/// Credentials support JSON serialization for API integration:
///
/// ```rust
/// use axum_gate::prelude::Credentials;
/// use serde_json;
///
/// // Deserialize from JSON (typical in REST APIs)
/// let json = r#"{"id": "user@example.com", "secret": "password123"}"#;
/// let credentials: Credentials<String> = serde_json::from_str(json)?;
///
/// // Serialize to JSON (less common, avoid logging)
/// let json = serde_json::to_string(&credentials)?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Different Identifier Types
///
/// ```rust
/// use axum_gate::prelude::Credentials;
/// use uuid::Uuid;
///
/// // String-based identifiers (email, username)
/// let email_creds = Credentials::new(&"user@domain.com".to_string(), "password");
/// let username_creds = Credentials::new(&"johndoe".to_string(), "secret123");
///
/// // UUID-based identifiers
/// let user_id = Uuid::now_v7();
/// let uuid_creds = Credentials::new(&user_id, "user_password");
///
/// // Custom identifier types work with any Clone type
/// #[derive(Clone)]
/// struct UserId(u64);
///
/// let user_id = UserId(12345);
/// let custom_creds = Credentials::new(&user_id, "password");
/// ```
///
/// # Integration with axum Extractors
///
/// ```rust
/// use axum::{Json, extract::State, http::StatusCode};
/// use axum_gate::prelude::Credentials;
///
/// // Extract credentials from JSON request body
/// async fn login_endpoint(
/// Json(credentials): Json<Credentials<String>>,
/// ) -> Result<String, StatusCode> {
/// // Process credentials...
/// Ok("Login successful".to_string())
/// }
///
/// // Extract credentials from form data
/// use axum::extract::Form;
/// async fn form_login(
/// Form(credentials): Form<Credentials<String>>,
/// ) -> Result<String, StatusCode> {
/// // Process form-submitted credentials...
/// Ok("Login successful".to_string())
/// }
/// ```