// 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 middleware 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) // - Pluggable serialization interface for custom data formats // - Secure password hashing with industry-standard algorithms // // Example usage: // // 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) // // // Clear authentication cookie (logout) // auth.Clear(w) // // // Get authenticated data // user, ok := auth.Get(r.Context()) // // Login handlers: // // type User struct { // Username string // Hash string // ID int // } // // // Implement PasswordUserDataStore interface // type UserStore struct{} // func (us UserStore) Fetch(username string) (User, bool, error) { // user, exists := database.FindUser(username) // return user, exists, nil // } // func (us UserStore) GetPassHash(user User) string { // return user.Hash // } // // // Password-based login // passwordConfig := kate.PasswordLoginConfig[User]{ // UserData: UserStore{}, // Redirects: kate.Redirects{ // Default: "/dashboard", // AllowedPrefixes: []string{"/app/", "/admin/"}, // FieldName: "redirect", // }, // } // http.Handle("POST /login", auth.PasswordLoginHandler(passwordConfig)) // // // Implement MagicLinkMailer interface // type UserMailer struct{} // func (um UserMailer) Fetch(email string) (User, bool, error) { // user, exists := database.FindUserByEmail(email) // return user, exists, nil // } // func (um UserMailer) SendEmail(user User, token string) error { // return emailService.SendMagicLink(user.Email, token) // } // // // Magic link authentication // magicConfig := kate.MagicLinkConfig[User]{ // Mailer: UserMailer{}, // Redirects: kate.Redirects{ Default: "/dashboard" }, // TokenExpiry: 15 * time.Minute, // TokenLocation: kate.TokenLocationQuery, // } // http.Handle("POST /magic-link", auth.MagicLinkLoginHandler(magicConfig)) // http.Handle("GET /verify", auth.MagicLinkVerifyHandler(magicConfig)) // // // OAuth2 authentication (Google example) // type UserDataStore struct{} // func (ds UserDataStore) GetOrCreateUser(email string) (User, error) { // user, exists := database.FindUserByEmail(email) // if exists { // return user, nil // } // return database.CreateUser(email) // } // func (ds UserDataStore) StoreState(state kate.OAuthState) (string, error) { // id := generateUniqueID() // return id, cache.Set(id, state, 10*time.Minute) // } // func (ds UserDataStore) GetAndClearState(id string) (*kate.OAuthState, error) { // var state kate.OAuthState // exists, err := cache.GetAndDelete(id, &state) // if !exists { // return nil, err // } // return &state, err // } // // oauthConfig := kate.GoogleOAuthConfig[User]( // "your-client-id", // "your-client-secret", // "https://yourapp.com/auth/callback", // UserDataStore{}, // ) // // Customize redirects if needed // oauthConfig.Redirects = kate.Redirects{ // Default: "/dashboard", // AllowedPrefixes: []string{"/app/", "/admin/"}, // FieldName: "redirect", // } // http.Handle("GET /auth/login", auth.OAuthLoginHandler(oauthConfig)) // http.Handle("GET /auth/callback", auth.OAuthCallbackHandler(oauthConfig)) // // Password hashing: // // // Hash a password with defaults // hash, err := kate.HashPassword("user-password", nil) // // // 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 package kate