430 lines
9.9 KiB
Markdown
430 lines
9.9 KiB
Markdown
# Milestone 4: Authentication System
|
|
|
|
**Status**: Planning
|
|
**Goal**: Secure developer authentication and app signing infrastructure.
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Authentication covers two areas:
|
|
1. **Developer authentication** - Login to portal, API access
|
|
2. **App signing** - Package integrity and developer verification
|
|
|
|
---
|
|
|
|
## Developer Authentication
|
|
|
|
### Methods Required
|
|
|
|
| Method | Use Case | Priority |
|
|
|--------|----------|----------|
|
|
| OAuth2 (GitHub) | Primary login | P0 |
|
|
| OAuth2 (Google) | Alternative login | P1 |
|
|
| Email + Password | Fallback | P2 |
|
|
| API Keys | CLI tools, CI/CD | P0 |
|
|
|
|
### OAuth2 Flow
|
|
|
|
```
|
|
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐
|
|
│ Browser │────►│ Portal │────►│ Provider │────►│ Callback│
|
|
└─────────┘ └─────────┘ │(GitHub) │ └────┬────┘
|
|
└──────────┘ │
|
|
▼
|
|
┌─────────────┐
|
|
│ Create/Link │
|
|
│ Account │
|
|
└─────────────┘
|
|
```
|
|
|
|
### OAuth2 Implementation
|
|
|
|
#### GitHub OAuth
|
|
|
|
```
|
|
Authorization URL: https://github.com/login/oauth/authorize
|
|
Token URL: https://github.com/login/oauth/access_token
|
|
User Info: https://api.github.com/user
|
|
Scopes: read:user, user:email
|
|
```
|
|
|
|
#### Google OAuth
|
|
|
|
```
|
|
Authorization URL: https://accounts.google.com/o/oauth2/v2/auth
|
|
Token URL: https://oauth2.googleapis.com/token
|
|
User Info: https://www.googleapis.com/oauth2/v2/userinfo
|
|
Scopes: openid, email, profile
|
|
```
|
|
|
|
### Session Management
|
|
|
|
#### JWT Tokens
|
|
|
|
```json
|
|
{
|
|
"sub": "dev_uuid",
|
|
"email": "dev@example.com",
|
|
"iat": 1704067200,
|
|
"exp": 1704153600,
|
|
"type": "access"
|
|
}
|
|
```
|
|
|
|
| Token Type | Lifetime | Storage |
|
|
|------------|----------|---------|
|
|
| Access Token | 1 hour | Memory/Cookie |
|
|
| Refresh Token | 30 days | HttpOnly Cookie |
|
|
|
|
#### Token Refresh Flow
|
|
|
|
```
|
|
1. Access token expires
|
|
2. Client sends refresh token
|
|
3. Server validates refresh token
|
|
4. Issue new access + refresh tokens
|
|
5. Invalidate old refresh token
|
|
```
|
|
|
|
### API Key Authentication
|
|
|
|
#### Key Format
|
|
|
|
```
|
|
mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
│ │ └── 32 random bytes (base62)
|
|
│ └── Environment (live/test)
|
|
└── Prefix (mosis key)
|
|
```
|
|
|
|
#### Key Storage
|
|
|
|
```sql
|
|
-- Only store hash, never the key itself
|
|
INSERT INTO api_keys (
|
|
developer_id,
|
|
name,
|
|
key_hash, -- bcrypt or argon2
|
|
key_prefix, -- "mk_live_abc" for display
|
|
permissions
|
|
) VALUES (...);
|
|
```
|
|
|
|
#### Key Permissions
|
|
|
|
```json
|
|
{
|
|
"permissions": [
|
|
"apps:read",
|
|
"apps:write",
|
|
"versions:upload",
|
|
"telemetry:read"
|
|
]
|
|
}
|
|
```
|
|
|
|
### Rate Limiting
|
|
|
|
| Endpoint Category | Limit | Window |
|
|
|-------------------|-------|--------|
|
|
| Auth endpoints | 10 | 1 minute |
|
|
| API (authenticated) | 1000 | 1 hour |
|
|
| API (per key) | 100 | 1 minute |
|
|
| Upload | 10 | 1 hour |
|
|
|
|
---
|
|
|
|
## App Signing
|
|
|
|
### Key Generation
|
|
|
|
#### Algorithm: Ed25519
|
|
|
|
```
|
|
Private key: 32 bytes (256 bits)
|
|
Public key: 32 bytes (256 bits)
|
|
Signature: 64 bytes (512 bits)
|
|
```
|
|
|
|
#### Why Ed25519?
|
|
- Fast signing and verification
|
|
- Small key and signature sizes
|
|
- No configuration choices (secure by default)
|
|
- Widely supported
|
|
|
|
### Key Generation Flow
|
|
|
|
```bash
|
|
# Developer generates keypair locally
|
|
mosis keys generate
|
|
|
|
# Output:
|
|
# Private key saved to: ~/.mosis/signing_key.pem
|
|
# Public key saved to: ~/.mosis/signing_key.pub
|
|
#
|
|
# Fingerprint: SHA256:xxxxx
|
|
#
|
|
# IMPORTANT: Keep your private key secure!
|
|
# Upload your public key to the developer portal.
|
|
```
|
|
|
|
### Key Format
|
|
|
|
#### Private Key (PEM)
|
|
|
|
```
|
|
-----BEGIN PRIVATE KEY-----
|
|
MC4CAQAwBQYDK2VwBCIEIGxxxxx...
|
|
-----END PRIVATE KEY-----
|
|
```
|
|
|
|
#### Public Key (PEM)
|
|
|
|
```
|
|
-----BEGIN PUBLIC KEY-----
|
|
MCowBQYDK2VwAyEAxxxxx...
|
|
-----END PUBLIC KEY-----
|
|
```
|
|
|
|
### Signing Flow
|
|
|
|
```
|
|
1. Build package (ZIP all files)
|
|
2. Generate MANIFEST.MF with SHA-256 hashes
|
|
3. Sign MANIFEST.MF with private key
|
|
4. Store signature in META-INF/CERT.SIG
|
|
5. Include public key in META-INF/CERT.PEM
|
|
```
|
|
|
|
#### MANIFEST.MF Example
|
|
|
|
```
|
|
Manifest-Version: 1.0
|
|
Created-By: mosis-cli 1.0.0
|
|
Package-Id: com.developer.myapp
|
|
Version-Code: 1
|
|
|
|
Name: manifest.json
|
|
SHA-256-Digest: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
|
|
|
|
Name: assets/main.rml
|
|
SHA-256-Digest: uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
|
|
```
|
|
|
|
### Verification Flow
|
|
|
|
```
|
|
1. Extract MANIFEST.MF from package
|
|
2. Extract CERT.SIG (signature)
|
|
3. Extract CERT.PEM (public key)
|
|
4. Verify signature of MANIFEST.MF using public key
|
|
5. Verify CERT.PEM matches registered developer key
|
|
6. Verify each file hash matches MANIFEST.MF entry
|
|
```
|
|
|
|
### Key Registration
|
|
|
|
```
|
|
Developer Portal:
|
|
├── Go to Settings > Signing Keys
|
|
├── Click "Add Key"
|
|
├── Paste public key (PEM format)
|
|
├── Verify fingerprint matches local
|
|
└── Key is now registered
|
|
|
|
Server stores:
|
|
├── public_key (PEM text)
|
|
├── fingerprint (SHA256 of public key)
|
|
├── created_at
|
|
└── is_active
|
|
```
|
|
|
|
### Key Rotation
|
|
|
|
```
|
|
1. Generate new keypair
|
|
2. Register new public key in portal
|
|
3. Sign new versions with new key
|
|
4. (Optional) Revoke old key after transition period
|
|
```
|
|
|
|
### Trust Model
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ Trust Chain │
|
|
├─────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Developer │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ Private Key ──signs──► Package │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ Public Key ──registered──► Portal │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ Portal ──verifies──► Signature │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ Device ──trusts──► Portal-verified packages │
|
|
│ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
### Password Storage (if used)
|
|
|
|
```
|
|
Algorithm: Argon2id
|
|
Memory: 64 MB
|
|
Iterations: 3
|
|
Parallelism: 4
|
|
Salt: 16 bytes random
|
|
```
|
|
|
|
### Token Security
|
|
|
|
- Access tokens: Short-lived, in-memory only
|
|
- Refresh tokens: HttpOnly, Secure, SameSite=Strict
|
|
- API keys: Hashed with bcrypt, shown once on creation
|
|
|
|
### Key Security
|
|
|
|
- Private keys never leave developer's machine
|
|
- Public keys verified via fingerprint
|
|
- Key compromise: Revoke immediately, re-sign apps
|
|
|
|
### Audit Logging
|
|
|
|
```sql
|
|
INSERT INTO auth_audit_log (
|
|
developer_id,
|
|
action, -- login, logout, key_create, key_revoke
|
|
ip_address,
|
|
user_agent,
|
|
success,
|
|
failure_reason,
|
|
timestamp
|
|
) VALUES (...);
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Authentication
|
|
|
|
```
|
|
POST /auth/oauth/github # Start GitHub OAuth
|
|
GET /auth/oauth/github/callback # GitHub callback
|
|
POST /auth/oauth/google # Start Google OAuth
|
|
GET /auth/oauth/google/callback # Google callback
|
|
POST /auth/refresh # Refresh tokens
|
|
POST /auth/logout # Invalidate tokens
|
|
GET /auth/me # Get current user
|
|
```
|
|
|
|
### API Keys
|
|
|
|
```
|
|
GET /api-keys # List keys
|
|
POST /api-keys # Create key
|
|
DELETE /api-keys/:id # Revoke key
|
|
```
|
|
|
|
### Signing Keys
|
|
|
|
```
|
|
GET /signing-keys # List keys
|
|
POST /signing-keys # Register key
|
|
DELETE /signing-keys/:id # Revoke key
|
|
GET /signing-keys/:id/verify # Verify a signature
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Libraries
|
|
|
|
### Node.js
|
|
|
|
```json
|
|
{
|
|
"passport": "OAuth strategies",
|
|
"jose": "JWT handling",
|
|
"@noble/ed25519": "Ed25519 signing",
|
|
"argon2": "Password hashing"
|
|
}
|
|
```
|
|
|
|
### Go
|
|
|
|
```go
|
|
import (
|
|
"golang.org/x/oauth2"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"crypto/ed25519"
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
```
|
|
|
|
### Rust
|
|
|
|
```toml
|
|
[dependencies]
|
|
oauth2 = "4.4"
|
|
jsonwebtoken = "9"
|
|
ed25519-dalek = "2"
|
|
argon2 = "0.5"
|
|
```
|
|
|
|
---
|
|
|
|
## Deliverables
|
|
|
|
- [ ] OAuth2 integration (GitHub)
|
|
- [ ] OAuth2 integration (Google)
|
|
- [ ] JWT token management
|
|
- [ ] API key generation and validation
|
|
- [ ] Ed25519 key generation tool
|
|
- [ ] Signature creation and verification
|
|
- [ ] Key registration API
|
|
- [ ] Audit logging
|
|
|
|
---
|
|
|
|
## Test Cases
|
|
|
|
| Test | Description |
|
|
|------|-------------|
|
|
| OAuthLogin | Complete OAuth flow |
|
|
| TokenRefresh | Refresh expired access token |
|
|
| InvalidToken | Reject tampered JWT |
|
|
| APIKeyAuth | Authenticate with API key |
|
|
| KeyGeneration | Generate valid Ed25519 keypair |
|
|
| SignPackage | Sign and verify package |
|
|
| InvalidSignature | Reject tampered package |
|
|
| KeyRevocation | Revoked key fails verification |
|
|
|
|
---
|
|
|
|
## Open Questions
|
|
|
|
1. Support for hardware security keys (YubiKey)?
|
|
2. Multi-factor authentication for portal?
|
|
3. Team accounts with role-based access?
|
|
4. Key escrow for enterprise customers?
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- [OAuth 2.0 RFC 6749](https://tools.ietf.org/html/rfc6749)
|
|
- [JWT RFC 7519](https://tools.ietf.org/html/rfc7519)
|
|
- [Ed25519 paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf)
|
|
- [OWASP Authentication Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
|