summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorT <t@tjp.lol>2025-06-26 11:42:17 -0600
committerT <t@tjp.lol>2025-07-01 17:50:49 -0600
commit639ad6a02cbb4b713434671ec09f309aa5410921 (patch)
tree7dde9cce8136636d11f2f7c961072984cfc705e7 /README.md
Create authentic_kate: user authentication for go HTTP applications
Diffstat (limited to 'README.md')
-rw-r--r--README.md203
1 files changed, 203 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d5d7882
--- /dev/null
+++ b/README.md
@@ -0,0 +1,203 @@
+# authentic_kate
+
+Package kate provides secure cookie-based authentication for HTTP applications.
+
+This package implements encrypted cookies with authenticated encryption.
+It supports generic types to allow storage of any serializable data in encrypted HTTP cookies.
+
+## Key features
+
+- Type-safe authentication data storage using Go generics
+- Authenticated encryption for secure cookie storage
+- HTTP middlewares for required and optional authentication
+- Ready-to-use login handlers for password, oauth, and magic link authentication
+- Configurable cookie properties (domain, path, HTTPS-only, max age)
+- Secure password hashing with industry-standard algorithms
+
+## Example usage
+
+```go
+type UserData struct {
+ ID int
+ Name string
+}
+
+// Implement SerDes interface for UserData
+type UserSerDes struct{}
+func (s UserSerDes) Serialize(w io.Writer, data UserData) error { /* ... */ }
+func (s UserSerDes) Deserialize(r io.Reader, data *UserData) error { /* ... */ }
+
+// Create authentication instance
+auth := kate.New("hex-encoded-32-byte-key", kate.AuthConfig[UserData]{
+ SerDes: UserSerDes{},
+ CookieName: "session",
+ HTTPSOnly: true,
+ MaxAge: 24 * time.Hour,
+})
+
+// Use as middleware
+http.Handle("GET /protected", auth.Required(protectedHandler))
+
+// Set authentication cookie
+user := UserData{ID: 123, Name: "John"}
+auth.Set(w, user)
+
+// Get authenticated data
+user, ok := auth.Get(r.Context())
+```
+
+## Login handlers
+
+The package provides ready-to-use HTTP handlers for several authentication methods:
+
+### Password-based login
+
+```go
+type User struct {
+ Username string
+ Hash string
+ ID int
+}
+
+// Implement PasswordUserDataStore interface
+type UserStore struct{}
+
+func (us UserStore) Fetch(username string) (User, bool, error) {
+ // Look up user in your database
+ user, exists := database.FindUser(username)
+ return user, exists, nil
+}
+
+func (us UserStore) GetPassHash(user User) string {
+ return user.Hash
+}
+
+// Configure password login
+passwordConfig := kate.PasswordLoginConfig[User]{
+ UserData: UserStore{},
+ Redirects: kate.Redirects{
+ Default: "/dashboard",
+ AllowedPrefixes: []string{"/app/", "/admin/"},
+ FieldName: "redirect",
+ },
+}
+
+// Create handler
+http.Handle("POST /login", auth.PasswordLoginHandler(passwordConfig))
+```
+
+### Magic link authentication
+
+```go
+// Implement MagicLinkMailer interface
+type UserMailer struct{}
+
+func (um UserMailer) Fetch(email string) (User, bool, error) {
+ // Look up user by email
+ user, exists := database.FindUserByEmail(email)
+ return user, exists, nil
+}
+
+func (um UserMailer) SendEmail(user User, token string) error {
+ // Send magic link email with the token
+ return emailService.SendMagicLink(user.Email, token)
+}
+
+// Configure magic link login
+magicConfig := kate.MagicLinkConfig[User]{
+ Mailer: UserMailer{},
+ Redirects: kate.Redirects{ Default: "/dashboard" },
+ TokenExpiry: 15 * time.Minute,
+ TokenLocation: kate.TokenLocationQuery, // or TokenLocationPath
+}
+
+// Create handlers
+http.Handle("POST /magic-link", auth.MagicLinkLoginHandler(magicConfig))
+http.Handle("GET /verify", auth.MagicLinkVerifyHandler(magicConfig))
+```
+
+### OAuth2 authentication
+
+```go
+// Implement the OAuthDataStore interface
+type UserDataStore struct{}
+
+func (ds UserDataStore) GetOrCreateUser(email string) (User, error) {
+ // Look up user by email, create if doesn't exist
+ if user, exists := database.FindUserByEmail(email); exists {
+ return user, nil
+ }
+ return database.CreateUser(email)
+}
+
+func (ds UserDataStore) StoreState(state kate.OAuthState) (string, error) {
+ // Generate unique state ID and store temporarily
+ id := generateUniqueID()
+ return id, cache.Set(id, state, 10*time.Minute)
+}
+
+func (ds UserDataStore) GetAndClearState(id string) (*kate.OAuthState, error) {
+ // Retrieve and delete state data
+ var state kate.OAuthState
+ exists, err := cache.GetAndDelete(id, &state)
+ if !exists {
+ return nil, err
+ }
+ return &state, err
+}
+
+// Configure Google OAuth2 login
+oauthConfig := kate.GoogleOAuthConfig[User](
+ "your-google-client-id",
+ "your-google-client-secret",
+ "https://yourapp.com/auth/callback",
+ UserDataStore{},
+)
+
+// Customize redirects and security settings
+oauthConfig.Redirects = kate.Redirects{
+ Default: "/dashboard",
+ AllowedPrefixes: []string{"/app/", "/admin/"},
+ FieldName: "redirect",
+}
+
+// Create handlers
+http.Handle("GET /auth/login", auth.OAuthLoginHandler(oauthConfig))
+http.Handle("GET /auth/callback", auth.OAuthCallbackHandler(oauthConfig))
+
+// GitHub OAuth2 is also supported
+githubConfig := kate.GitHubOAuthConfig[User](
+ "your-github-client-id",
+ "your-github-client-secret",
+ "https://yourapp.com/auth/github/callback",
+ UserDataStore{},
+)
+```
+
+## Password hashing
+
+The package provides secure password hashing functions using Argon2id:
+
+```go
+// Hash a password with secure defaults
+hash, err := kate.HashPassword("user-password", nil)
+if err != nil {
+ // Handle error
+}
+
+// Verify a password
+match, err := kate.ComparePassword("user-password", hash)
+if err != nil {
+ // Handle malformed hash error
+}
+if match {
+ // Password is correct
+}
+```
+
+## Cryptographic algorithms
+
+This package uses the following cryptographic algorithms:
+
+- **Token encryption**: XSalsa20 stream cipher with Poly1305 MAC for authenticated encryption (compatible with libsodium secretbox)
+- **Password hashing**: Argon2id with secure default parameters and PHC format storage