update M04 auth with Go implementation details
This commit is contained in:
@@ -1,8 +1,27 @@
|
|||||||
# Milestone 4: Authentication System
|
# Milestone 4: Authentication System
|
||||||
|
|
||||||
**Status**: Planning
|
**Status**: Decided
|
||||||
**Goal**: Secure developer authentication and app signing infrastructure.
|
**Goal**: Secure developer authentication and app signing infrastructure.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**Custom JWT + OAuth2** with Go standard library crypto:
|
||||||
|
|
||||||
|
```
|
||||||
|
OAuth2: golang.org/x/oauth2 (GitHub, Google)
|
||||||
|
JWT: github.com/golang-jwt/jwt/v5
|
||||||
|
Signing: crypto/ed25519 (stdlib)
|
||||||
|
Password Hash: golang.org/x/crypto/argon2
|
||||||
|
API Key Hash: golang.org/x/crypto/bcrypt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rationale
|
||||||
|
|
||||||
|
1. **Go stdlib crypto** - Ed25519 built into Go, no external deps
|
||||||
|
2. **Simple JWT** - golang-jwt is battle-tested, minimal
|
||||||
|
3. **Stateless tokens** - No token store needed (SQLite handles refresh token revocation)
|
||||||
|
4. **OAuth-first** - GitHub OAuth for most developers, minimal password handling
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@@ -348,49 +367,94 @@ GET /signing-keys/:id/verify # Verify a signature
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Implementation Libraries
|
## Implementation (Go)
|
||||||
|
|
||||||
### Node.js
|
### Dependencies
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"passport": "OAuth strategies",
|
|
||||||
"jose": "JWT handling",
|
|
||||||
"@noble/ed25519": "Ed25519 signing",
|
|
||||||
"argon2": "Password hashing"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Go
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
// OAuth2
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/github"
|
||||||
|
"golang.org/x/oauth2/google"
|
||||||
|
|
||||||
|
// JWT
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
|
||||||
|
// Cryptography (all stdlib)
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
// Password/Key hashing
|
||||||
"golang.org/x/crypto/argon2"
|
"golang.org/x/crypto/argon2"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Rust
|
### OAuth2 Config
|
||||||
|
|
||||||
```toml
|
```go
|
||||||
[dependencies]
|
var githubOAuth = &oauth2.Config{
|
||||||
oauth2 = "4.4"
|
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
||||||
jsonwebtoken = "9"
|
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
||||||
ed25519-dalek = "2"
|
Endpoint: github.Endpoint,
|
||||||
argon2 = "0.5"
|
Scopes: []string{"read:user", "user:email"},
|
||||||
|
RedirectURL: "https://portal.mosis.dev/auth/github/callback",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### JWT Generation
|
||||||
|
|
||||||
|
```go
|
||||||
|
func generateAccessToken(developerID string) (string, error) {
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"sub": developerID,
|
||||||
|
"type": "access",
|
||||||
|
"iat": time.Now().Unix(),
|
||||||
|
"exp": time.Now().Add(time.Hour).Unix(),
|
||||||
|
}
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ed25519 Signing
|
||||||
|
|
||||||
|
```go
|
||||||
|
func signManifest(manifest []byte, privateKey ed25519.PrivateKey) []byte {
|
||||||
|
return ed25519.Sign(privateKey, manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySignature(manifest, signature []byte, publicKey ed25519.PublicKey) bool {
|
||||||
|
return ed25519.Verify(publicKey, manifest, signature)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Key Hashing
|
||||||
|
|
||||||
|
```go
|
||||||
|
func hashAPIKey(key string) (string, error) {
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(key), bcrypt.DefaultCost)
|
||||||
|
return string(hash), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyAPIKey(key, hash string) bool {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(key)) == nil
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Deliverables
|
## Deliverables
|
||||||
|
|
||||||
- [ ] OAuth2 integration (GitHub)
|
- [x] Auth approach decided (OAuth2 + JWT + API Keys)
|
||||||
- [ ] OAuth2 integration (Google)
|
- [x] Crypto libraries selected (Go stdlib + golang-jwt)
|
||||||
|
- [ ] OAuth2 integration (GitHub) - P0
|
||||||
|
- [ ] OAuth2 integration (Google) - P1
|
||||||
- [ ] JWT token management
|
- [ ] JWT token management
|
||||||
- [ ] API key generation and validation
|
- [ ] API key generation and validation
|
||||||
- [ ] Ed25519 key generation tool
|
- [ ] Ed25519 key generation (CLI tool)
|
||||||
- [ ] Signature creation and verification
|
- [ ] Signature creation and verification
|
||||||
- [ ] Key registration API
|
- [ ] Key registration API
|
||||||
- [ ] Audit logging
|
- [ ] Audit logging
|
||||||
@@ -414,10 +478,10 @@ argon2 = "0.5"
|
|||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
1. Support for hardware security keys (YubiKey)?
|
1. ~~Support for hardware security keys (YubiKey)?~~ → Defer to post-MVP
|
||||||
2. Multi-factor authentication for portal?
|
2. ~~Multi-factor authentication for portal?~~ → Defer to post-MVP
|
||||||
3. Team accounts with role-based access?
|
3. Team accounts with role-based access? → Consider for v1.1
|
||||||
4. Key escrow for enterprise customers?
|
4. ~~Key escrow for enterprise customers?~~ → Not needed for self-hosted
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user