pub struct AuthService {
pub jwt_config: JwtConfig,
}
Expand description
Authentication service that handles ECDSA challenge-based authentication
This service provides stateless authentication operations:
- Challenge generation for clients to sign
- Signature verification against challenges
- JWT token creation for authenticated sessions
- JWT token validation
The service does not store any state - developers must handle challenge storage and session management in their own systems.
§Example
use ecdsa_jwt::{AuthService, JwtConfig};
use secrecy::Secret;
use base64::prelude::*;
let config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("your-secret")),
ttl: 3600, // 1 hour
};
let auth_service = AuthService::new(config);
Fields§
§jwt_config: JwtConfig
Implementations§
Source§impl AuthService
impl AuthService
Sourcepub fn new(jwt_config: JwtConfig) -> Self
pub fn new(jwt_config: JwtConfig) -> Self
Create a new authentication service with the given JWT configuration
§Arguments
jwt_config
- Configuration containing JWT secret and token lifetime
§Example
use ecdsa_jwt::{auth::{AuthService},config::JwtConfig};
use secrecy::Secret;
use base64::prelude::*;
let config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("your-secret")),
ttl: 3600, // 1 hour
};
let auth_service = AuthService::new(config);
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 println!("ECDSA-JWT Basic Usage Example");
13
14 // 1. Setup authentication service
15 let jwt_config = JwtConfig {
16 secret: Secret::new(BASE64_STANDARD.encode("example-secret-key")),
17 ttl: 3600, // 1 hour
18 };
19 let auth_service = AuthService::new(jwt_config);
20
21 // 2. Simulate challenge storage (in real app, use Redis/DB)
22 let mut challenges: HashMap<String, String> = HashMap::new();
23
24 // 3. Generate challenge
25 let challenge = auth_service.generate_challenge();
26 let session_id = "example-session-123";
27 challenges.insert(session_id.to_string(), challenge.clone());
28
29 println!("Generated challenge: {challenge}");
30 println!("Stored with session ID: {session_id}");
31
32 // 4. Simulate client authentication (this would normally fail without real signature)
33 println!("\n Authentication attempt...");
34
35 let auth_request = AuthRequest {
36 challenge,
37 signature: "dummy-signature-for-example".to_string(),
38 public_key: "-----BEGIN PUBLIC KEY-----\nDummyKeyForExample\n-----END PUBLIC KEY-----"
39 .to_string(),
40 };
41
42 // This will fail, but demonstrates the API structure
43 match auth_service.authenticate(auth_request, false) {
44 Ok(response) => {
45 println!("Authentication successful!");
46 println!(" JWT Token: {}", response.session_token);
47 println!(" Session ID: {}", response.session_id);
48 println!(" Expires at: {}", response.expires_at);
49 }
50 Err(e) => {
51 println!(" Authentication failed (expected with dummy data): {e}");
52 println!(" In real usage, provide valid signature and public key.");
53 }
54 }
55
56 // 5. Demonstrate JWT validation with a real token
57 println!("\nJWT Token Operations...");
58
59 let session_id = uuid::Uuid::new_v4();
60 let jwt_token = ecdsa_jwt::crypto::jwt::create_jwt(session_id, None, &auth_service.jwt_config)?;
61
62 println!("Created JWT: {}...", &jwt_token[..50]);
63
64 match auth_service.validate_session(&jwt_token) {
65 Ok(claims) => {
66 println!("Token validation successful!");
67 println!("User/Session ID: {}", claims.sub);
68 println!("Issued at: {}", claims.iat);
69 println!("Expires at: {}", claims.exp);
70 }
71 Err(e) => {
72 println!("Token validation failed: {e}");
73 }
74 }
75
76 println!("\nExample completed! Check the documentation for real implementation details.");
77 Ok(())
78}
Sourcepub fn generate_challenge(&self) -> String
pub fn generate_challenge(&self) -> String
Generate a cryptographically secure random challenge
Creates a 32-byte random challenge encoded as base64. This challenge should be:
- Sent to the client
- Stored temporarily by the server (with expiration)
- Signed by the client using their private key
- Submitted back with the signature for verification
§Returns
Base64-encoded 32-byte random challenge
§Example
use ecdsa_jwt::{auth::{AuthService},config::JwtConfig};
use secrecy::Secret;
use base64::prelude::*;
let config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("your-secret")),
ttl: 3600, // 1 hour
};
let auth_service = AuthService::new(config);
let challenge = auth_service.generate_challenge();
// Store this challenge with a session ID and expiration time
// Send challenge to client for signing
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 println!("ECDSA-JWT Basic Usage Example");
13
14 // 1. Setup authentication service
15 let jwt_config = JwtConfig {
16 secret: Secret::new(BASE64_STANDARD.encode("example-secret-key")),
17 ttl: 3600, // 1 hour
18 };
19 let auth_service = AuthService::new(jwt_config);
20
21 // 2. Simulate challenge storage (in real app, use Redis/DB)
22 let mut challenges: HashMap<String, String> = HashMap::new();
23
24 // 3. Generate challenge
25 let challenge = auth_service.generate_challenge();
26 let session_id = "example-session-123";
27 challenges.insert(session_id.to_string(), challenge.clone());
28
29 println!("Generated challenge: {challenge}");
30 println!("Stored with session ID: {session_id}");
31
32 // 4. Simulate client authentication (this would normally fail without real signature)
33 println!("\n Authentication attempt...");
34
35 let auth_request = AuthRequest {
36 challenge,
37 signature: "dummy-signature-for-example".to_string(),
38 public_key: "-----BEGIN PUBLIC KEY-----\nDummyKeyForExample\n-----END PUBLIC KEY-----"
39 .to_string(),
40 };
41
42 // This will fail, but demonstrates the API structure
43 match auth_service.authenticate(auth_request, false) {
44 Ok(response) => {
45 println!("Authentication successful!");
46 println!(" JWT Token: {}", response.session_token);
47 println!(" Session ID: {}", response.session_id);
48 println!(" Expires at: {}", response.expires_at);
49 }
50 Err(e) => {
51 println!(" Authentication failed (expected with dummy data): {e}");
52 println!(" In real usage, provide valid signature and public key.");
53 }
54 }
55
56 // 5. Demonstrate JWT validation with a real token
57 println!("\nJWT Token Operations...");
58
59 let session_id = uuid::Uuid::new_v4();
60 let jwt_token = ecdsa_jwt::crypto::jwt::create_jwt(session_id, None, &auth_service.jwt_config)?;
61
62 println!("Created JWT: {}...", &jwt_token[..50]);
63
64 match auth_service.validate_session(&jwt_token) {
65 Ok(claims) => {
66 println!("Token validation successful!");
67 println!("User/Session ID: {}", claims.sub);
68 println!("Issued at: {}", claims.iat);
69 println!("Expires at: {}", claims.exp);
70 }
71 Err(e) => {
72 println!("Token validation failed: {e}");
73 }
74 }
75
76 println!("\nExample completed! Check the documentation for real implementation details.");
77 Ok(())
78}
Sourcepub fn authenticate(
&self,
auth_request: AuthRequest,
include_public_key: bool,
) -> Result<AuthResponse>
pub fn authenticate( &self, auth_request: AuthRequest, include_public_key: bool, ) -> Result<AuthResponse>
Authenticate a client by verifying their signed challenge
This is the core authentication method that:
- Validates all input parameters
- Decodes base64-encoded challenge and signature
- Verifies the ECDSA signature using the provided public key
- Creates and returns a JWT token on successful verification
§Arguments
auth_request
- Contains challenge, signature, and public key
§Returns
Ok(AuthResponse)
- Authentication successful, contains JWT tokenErr(AuthError)
- Authentication failed with specific error details
§Errors
InvalidPublicKey
- Public key is empty or malformedInvalidChallenge
- Challenge is empty or invalidInvalidSignature
- Signature is empty, malformed, or verification failedBase64Error
- Challenge or signature has invalid base64 encodingCryptoError
- Unexpected cryptographic operation failure
§Example
use ecdsa_jwt::{auth::{AuthService, AuthRequest},config::JwtConfig};
use secrecy::Secret;
use base64::prelude::*;
let config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("your-secret")),
ttl: 3600, // 1 hour
};
let auth_request = AuthRequest {
challenge: "stored_challenge".to_string(),
signature: "client_signature".to_string(),
public_key: "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----".to_string(),
};
let auth_service = AuthService::new(config);
match auth_service.authenticate(auth_request, true) { // true = include public key in JWT
Ok(response) => {
println!("Authentication successful!");
println!("JWT: {}", response.session_token);
}
Err(e) => println!("Authentication failed: {}", e),
}
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 println!("ECDSA-JWT Basic Usage Example");
13
14 // 1. Setup authentication service
15 let jwt_config = JwtConfig {
16 secret: Secret::new(BASE64_STANDARD.encode("example-secret-key")),
17 ttl: 3600, // 1 hour
18 };
19 let auth_service = AuthService::new(jwt_config);
20
21 // 2. Simulate challenge storage (in real app, use Redis/DB)
22 let mut challenges: HashMap<String, String> = HashMap::new();
23
24 // 3. Generate challenge
25 let challenge = auth_service.generate_challenge();
26 let session_id = "example-session-123";
27 challenges.insert(session_id.to_string(), challenge.clone());
28
29 println!("Generated challenge: {challenge}");
30 println!("Stored with session ID: {session_id}");
31
32 // 4. Simulate client authentication (this would normally fail without real signature)
33 println!("\n Authentication attempt...");
34
35 let auth_request = AuthRequest {
36 challenge,
37 signature: "dummy-signature-for-example".to_string(),
38 public_key: "-----BEGIN PUBLIC KEY-----\nDummyKeyForExample\n-----END PUBLIC KEY-----"
39 .to_string(),
40 };
41
42 // This will fail, but demonstrates the API structure
43 match auth_service.authenticate(auth_request, false) {
44 Ok(response) => {
45 println!("Authentication successful!");
46 println!(" JWT Token: {}", response.session_token);
47 println!(" Session ID: {}", response.session_id);
48 println!(" Expires at: {}", response.expires_at);
49 }
50 Err(e) => {
51 println!(" Authentication failed (expected with dummy data): {e}");
52 println!(" In real usage, provide valid signature and public key.");
53 }
54 }
55
56 // 5. Demonstrate JWT validation with a real token
57 println!("\nJWT Token Operations...");
58
59 let session_id = uuid::Uuid::new_v4();
60 let jwt_token = ecdsa_jwt::crypto::jwt::create_jwt(session_id, None, &auth_service.jwt_config)?;
61
62 println!("Created JWT: {}...", &jwt_token[..50]);
63
64 match auth_service.validate_session(&jwt_token) {
65 Ok(claims) => {
66 println!("Token validation successful!");
67 println!("User/Session ID: {}", claims.sub);
68 println!("Issued at: {}", claims.iat);
69 println!("Expires at: {}", claims.exp);
70 }
71 Err(e) => {
72 println!("Token validation failed: {e}");
73 }
74 }
75
76 println!("\nExample completed! Check the documentation for real implementation details.");
77 Ok(())
78}
Sourcepub fn validate_session(&self, token: &str) -> Result<Claims>
pub fn validate_session(&self, token: &str) -> Result<Claims>
Validate a JWT session token
Verifies that a JWT token is:
- Properly formatted
- Signed with the correct secret
- Not expired
- Contains valid claims
§Arguments
token
- JWT token string to validate
§Returns
Ok(Claims)
- Token is valid, returns parsed claimsErr(AuthError)
- Token is invalid, expired, or malformed
§Example
use ecdsa_jwt::{auth::{AuthService, AuthRequest},config::JwtConfig};
use secrecy::Secret;
use base64::prelude::*;
let config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("your-secret")),
ttl: 3600, // 1 hour
};
let auth_service = AuthService::new(config);
let jwt_token = "token";
match auth_service.validate_session(&jwt_token) {
Ok(claims) => {
println!("Valid session for user: {}", claims.sub);
// Allow access to protected resource
}
Err(_) => {
println!("Invalid token - access denied");
// Return 401 Unauthorized
}
}
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 println!("ECDSA-JWT Basic Usage Example");
13
14 // 1. Setup authentication service
15 let jwt_config = JwtConfig {
16 secret: Secret::new(BASE64_STANDARD.encode("example-secret-key")),
17 ttl: 3600, // 1 hour
18 };
19 let auth_service = AuthService::new(jwt_config);
20
21 // 2. Simulate challenge storage (in real app, use Redis/DB)
22 let mut challenges: HashMap<String, String> = HashMap::new();
23
24 // 3. Generate challenge
25 let challenge = auth_service.generate_challenge();
26 let session_id = "example-session-123";
27 challenges.insert(session_id.to_string(), challenge.clone());
28
29 println!("Generated challenge: {challenge}");
30 println!("Stored with session ID: {session_id}");
31
32 // 4. Simulate client authentication (this would normally fail without real signature)
33 println!("\n Authentication attempt...");
34
35 let auth_request = AuthRequest {
36 challenge,
37 signature: "dummy-signature-for-example".to_string(),
38 public_key: "-----BEGIN PUBLIC KEY-----\nDummyKeyForExample\n-----END PUBLIC KEY-----"
39 .to_string(),
40 };
41
42 // This will fail, but demonstrates the API structure
43 match auth_service.authenticate(auth_request, false) {
44 Ok(response) => {
45 println!("Authentication successful!");
46 println!(" JWT Token: {}", response.session_token);
47 println!(" Session ID: {}", response.session_id);
48 println!(" Expires at: {}", response.expires_at);
49 }
50 Err(e) => {
51 println!(" Authentication failed (expected with dummy data): {e}");
52 println!(" In real usage, provide valid signature and public key.");
53 }
54 }
55
56 // 5. Demonstrate JWT validation with a real token
57 println!("\nJWT Token Operations...");
58
59 let session_id = uuid::Uuid::new_v4();
60 let jwt_token = ecdsa_jwt::crypto::jwt::create_jwt(session_id, None, &auth_service.jwt_config)?;
61
62 println!("Created JWT: {}...", &jwt_token[..50]);
63
64 match auth_service.validate_session(&jwt_token) {
65 Ok(claims) => {
66 println!("Token validation successful!");
67 println!("User/Session ID: {}", claims.sub);
68 println!("Issued at: {}", claims.iat);
69 println!("Expires at: {}", claims.exp);
70 }
71 Err(e) => {
72 println!("Token validation failed: {e}");
73 }
74 }
75
76 println!("\nExample completed! Check the documentation for real implementation details.");
77 Ok(())
78}
Sourcepub fn verify_signature_from_jwt(
&self,
jwt_token: &str,
challenge: &[u8],
signature: &[u8],
) -> Result<()>
pub fn verify_signature_from_jwt( &self, jwt_token: &str, challenge: &[u8], signature: &[u8], ) -> Result<()>
Verify a signature using the public key from JWT claims
This method extracts the public key from the JWT and uses it to verify a signature, eliminating the need to pass the public key separately.
§Arguments
jwt_token
- JWT token containing public key informationchallenge
- Challenge bytes that were signedsignature
- Signature bytes to verify
§Returns
Ok(())
if signature is validErr(AuthError)
if verification fails
§Example
use ecdsa_jwt::auth::AuthService;
use ecdsa_jwt::config::JwtConfig;
use secrecy::Secret;
use base64::prelude::*;
let jwt_config = JwtConfig {
secret: Secret::new(BASE64_STANDARD.encode("test-secret")),
ttl: 3600,
};
let auth_service = AuthService::new(jwt_config);
// This would normally be a real JWT token with embedded public key
let jwt_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...";
let challenge = b"challenge bytes";
let signature = &[0x30, 0x44, 0x02, 0x20]; // Example DER signature
// Note: This will fail with a real JWT that doesn't contain a public key
// This is just demonstrating the API usage
let _result = auth_service.verify_signature_from_jwt(jwt_token, challenge, signature);