- Created SelfFreezoneClient in Self components
- Wraps SDK FreezoneScriptClient for Self-specific operations
- Implements send_verification_email method
- Uses Rhai script template for email verification
- Includes template variable substitution
- Added serde-wasm-bindgen dependency
Usage:
let client = SelfFreezoneClient::builder()
.supervisor_url("http://localhost:8080")
.secret("my-secret")
.build()?;
client.send_verification_email(
"user@example.com",
"123456",
"https://verify.com/abc"
).await?;
300 lines
8.6 KiB
Markdown
300 lines
8.6 KiB
Markdown
# Authentication Flows
|
|
|
|
## Overview
|
|
|
|
Self implements a cryptographic challenge-response authentication system that eliminates the need for passwords while providing strong security guarantees. The system supports both new user registration and existing user authentication flows.
|
|
|
|
## Registration Flow
|
|
|
|
### Step-by-Step Process
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant U as User
|
|
participant C as Client (Browser)
|
|
participant S as Server
|
|
participant E as Email System
|
|
|
|
Note over U,E: Phase 1: Email Verification
|
|
U->>C: Enter name and email
|
|
C->>S: POST /api/send-verification
|
|
S->>E: Generate verification link
|
|
S->>C: Verification sent response
|
|
S-->>U: Display verification link (dev mode)
|
|
|
|
Note over U,E: Phase 2: Email Confirmation
|
|
U->>S: Click verification link
|
|
S->>S: Mark email as verified
|
|
S->>C: SSE notification (verified)
|
|
C->>C: Update UI to show verified status
|
|
|
|
Note over U,E: Phase 3: Key Generation
|
|
U->>C: Click "Generate Keys"
|
|
C->>C: Generate secp256k1 key pair
|
|
C->>C: Display private key for backup
|
|
U->>C: Copy private key (mandatory)
|
|
U->>C: Enter encryption password
|
|
C->>C: Encrypt private key with AES-256-GCM
|
|
C->>C: Store encrypted key in localStorage
|
|
|
|
Note over U,E: Phase 4: Key Confirmation
|
|
U->>C: Paste private key for confirmation
|
|
C->>C: Verify pasted key matches generated key
|
|
U->>C: Confirm registration
|
|
C->>S: POST /api/register {email, name, public_key}
|
|
S->>S: Verify email is confirmed
|
|
S->>S: Store user record
|
|
S->>C: Registration success response
|
|
C->>C: Complete registration flow
|
|
```
|
|
|
|
### Registration Data Flow
|
|
|
|
1. **Email Collection**
|
|
```rust
|
|
struct EmailVerificationRequest {
|
|
email: String,
|
|
}
|
|
```
|
|
|
|
2. **Verification Status**
|
|
```rust
|
|
struct VerificationStatus {
|
|
email: String,
|
|
verified: bool,
|
|
verification_token: String,
|
|
}
|
|
```
|
|
|
|
3. **Key Generation** (Client-side)
|
|
```rust
|
|
let keypair = generate_keypair()?;
|
|
let encrypted_key = encrypt_private_key(&keypair.private_key, &password)?;
|
|
```
|
|
|
|
4. **Registration Completion**
|
|
```rust
|
|
struct RegistrationRequest {
|
|
email: String,
|
|
name: String,
|
|
public_key: String,
|
|
}
|
|
```
|
|
|
|
### Security Measures
|
|
|
|
- **Email Verification**: Prevents unauthorized registrations
|
|
- **Key Backup Confirmation**: Ensures user has saved private key
|
|
- **Client-side Encryption**: Private key never transmitted unencrypted
|
|
- **Secure Random Generation**: Cryptographically secure key generation
|
|
- **Password Validation**: Minimum 8 character password requirement
|
|
|
|
## Login Flow
|
|
|
|
### Step-by-Step Process
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant U as User
|
|
participant C as Client (Browser)
|
|
participant S as Server
|
|
participant V as Vault System
|
|
|
|
Note over U,V: Phase 1: Identity Input
|
|
U->>C: Enter public key or select identity
|
|
C->>C: Validate public key format
|
|
|
|
Note over U,V: Phase 2: Challenge Generation
|
|
C->>S: Request authentication challenge
|
|
S->>S: Generate random challenge
|
|
S->>C: Return challenge + session info
|
|
|
|
Note over U,V: Phase 3: Key Decryption
|
|
U->>C: Enter password
|
|
C->>V: Retrieve encrypted private key
|
|
V->>C: Return encrypted key data
|
|
C->>C: Decrypt private key with password
|
|
|
|
Note over U,V: Phase 4: Challenge Response
|
|
C->>C: Sign challenge with private key
|
|
C->>S: POST /oauth/token {signature, public_key, challenge}
|
|
S->>S: Verify signature against public key
|
|
S->>S: Generate JWT token
|
|
S->>C: Return access token
|
|
|
|
Note over U,V: Phase 5: Session Establishment
|
|
C->>C: Store JWT token
|
|
C->>S: GET /oauth/userinfo (with Bearer token)
|
|
S->>C: Return user profile
|
|
C->>C: Complete login flow
|
|
```
|
|
|
|
### OAuth 2.0 Token Request
|
|
|
|
The login process follows OAuth 2.0 client credentials flow with cryptographic assertions:
|
|
|
|
```rust
|
|
struct LoginRequest {
|
|
grant_type: String, // "client_credentials"
|
|
client_assertion_type: String, // "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
|
client_assertion: String, // Signed JWT containing challenge response
|
|
public_key: String, // User's public key (client identifier)
|
|
challenge: String, // Server-provided challenge
|
|
scope: String, // Requested permissions
|
|
}
|
|
```
|
|
|
|
### JWT Token Structure
|
|
|
|
```rust
|
|
struct Claims {
|
|
sub: String, // Subject (public key)
|
|
iss: String, // Issuer ("self-sovereign-identity")
|
|
aud: String, // Audience ("identity-server")
|
|
exp: usize, // Expiration time (1 hour)
|
|
iat: usize, // Issued at time
|
|
scope: String, // Granted scopes
|
|
}
|
|
```
|
|
|
|
### Challenge-Response Mechanism
|
|
|
|
1. **Challenge Generation**
|
|
```rust
|
|
let challenge = Uuid::new_v4().to_string();
|
|
```
|
|
|
|
2. **Signature Creation** (Client-side)
|
|
```rust
|
|
let signature = keypair.sign(&challenge)?;
|
|
```
|
|
|
|
3. **Signature Verification** (Server-side)
|
|
```rust
|
|
fn verify_signature(public_key: &str, challenge: &str, signature: &str) -> bool {
|
|
// Verify signature matches challenge using public key
|
|
}
|
|
```
|
|
|
|
## Vault-Based Authentication
|
|
|
|
### Multi-Key Management
|
|
|
|
The vault system allows users to store multiple encrypted keys and authenticate with any of them:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant U as User
|
|
participant C as Client
|
|
participant V as Vault Manager
|
|
participant S as Server
|
|
|
|
U->>C: Select identity from vault
|
|
C->>V: List available identities
|
|
V->>C: Return identity list
|
|
U->>C: Choose identity and enter password
|
|
C->>V: Decrypt selected identity key
|
|
V->>C: Return decrypted private key
|
|
C->>S: Authenticate with selected identity
|
|
S->>C: Return session for selected identity
|
|
```
|
|
|
|
### Vault Data Structure
|
|
|
|
```rust
|
|
struct VaultEntry {
|
|
id: String,
|
|
name: String,
|
|
email: String,
|
|
public_key: String,
|
|
encrypted_private_key: EncryptedPrivateKey,
|
|
created_at: String,
|
|
}
|
|
|
|
struct EncryptedPrivateKey {
|
|
encrypted_data: String, // Base64 encoded ciphertext
|
|
nonce: String, // Base64 encoded nonce
|
|
salt: String, // Base64 encoded salt
|
|
}
|
|
```
|
|
|
|
## Session Management
|
|
|
|
### JWT Token Lifecycle
|
|
|
|
1. **Token Issuance**
|
|
- Generated after successful authentication
|
|
- Contains user's public key as subject
|
|
- 1-hour expiration time
|
|
- Signed with server secret
|
|
|
|
2. **Token Usage**
|
|
- Included in Authorization header as Bearer token
|
|
- Required for accessing protected endpoints
|
|
- Validated on each request
|
|
|
|
3. **Token Refresh**
|
|
- Currently requires re-authentication
|
|
- Future: Refresh token mechanism
|
|
|
|
### Session Storage
|
|
|
|
```javascript
|
|
// Client-side session storage
|
|
localStorage.setItem('jwt_token', access_token);
|
|
localStorage.setItem('current_identity', public_key);
|
|
localStorage.setItem('session_expires', expiration_time);
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Registration Errors
|
|
|
|
- **Email Not Verified**: User must complete email verification
|
|
- **Invalid Email Format**: Client-side validation prevents submission
|
|
- **Key Generation Failed**: Retry with new random seed
|
|
- **Encryption Failed**: Check password strength and retry
|
|
- **Server Unavailable**: Retry with exponential backoff
|
|
|
|
### Authentication Errors
|
|
|
|
- **Invalid Public Key**: Key format validation and user feedback
|
|
- **Wrong Password**: Decryption failure, prompt for correct password
|
|
- **Signature Verification Failed**: Invalid key or challenge tampering
|
|
- **Token Expired**: Automatic re-authentication flow
|
|
- **User Not Found**: Public key not registered, redirect to registration
|
|
|
|
### Error Response Format
|
|
|
|
```rust
|
|
struct ErrorResponse {
|
|
error: String, // OAuth 2.0 error code
|
|
error_description: String, // Human-readable description
|
|
error_uri: Option<String>, // Optional documentation link
|
|
}
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Attack Mitigation
|
|
|
|
1. **Replay Attacks**: Challenges are single-use and time-limited
|
|
2. **Man-in-the-Middle**: HTTPS encryption for all communications
|
|
3. **Key Theft**: Private keys encrypted with user passwords
|
|
4. **Brute Force**: Rate limiting on authentication attempts
|
|
5. **Session Hijacking**: JWT tokens with short expiration times
|
|
|
|
### Privacy Protection
|
|
|
|
- **No Password Storage**: Server never sees user passwords
|
|
- **Minimal Data Collection**: Only email and public key stored
|
|
- **Local Key Storage**: Private keys never leave user's device
|
|
- **Anonymous Usage**: Public keys don't reveal personal information
|
|
|
|
### Compliance Considerations
|
|
|
|
- **GDPR**: Users control their own data, right to deletion
|
|
- **OAuth 2.0**: Standard token-based authentication
|
|
- **OpenID Connect**: Compatible user info endpoint
|
|
- **WebAuthn**: Future integration for hardware token support
|