diff options
author | T <t@tjp.lol> | 2025-06-26 11:42:17 -0600 |
---|---|---|
committer | T <t@tjp.lol> | 2025-07-01 17:50:49 -0600 |
commit | 639ad6a02cbb4b713434671ec09f309aa5410921 (patch) | |
tree | 7dde9cce8136636d11f2f7c961072984cfc705e7 /README.md |
Create authentic_kate: user authentication for go HTTP applications
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 203 |
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 |