Using ezauth as a Library
Embedding ezauth directly into your Go application provides the most seamless integration. It allows you to use ezauth's middleware and internal services directly within your code. Everything you need to secure a route is exposed on the EzAuth instance returned by New.
Basic Integration
Here is a complete example of how to integrate ezauth into a chi router, ensuring the session middleware is correctly configured:
package main
import (
"fmt"
"log"
"net/http"
"os"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/josuebrunel/ezauth"
"github.com/josuebrunel/ezauth/pkg/config"
)
func main() {
// 1. Setup Config
os.Setenv("EZAUTH_API_KEY", "my-api-key")
os.Setenv("EZAUTH_JWT_SECRET", "my-jwt-key-at-least-32-characters-long") // HS256 requires >= 32 chars
// ... set other necessary env vars
cfg, err := config.LoadConfig()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// 2. Initialize EzAuth
auth, err := ezauth.New(&cfg, "")
if err != nil {
log.Fatalf("Failed to initialize auth: %v", err)
}
// 3. Run migrations
if err := auth.Migrate(); err != nil {
log.Fatalf("Failed to migrate: %v", err)
}
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// 4. Add session middleware (handles sessions and user loading)
r.Use(auth.SessionMiddleware)
// 5. Mount Auth Routes
r.Mount("/auth", auth.Handler)
// Public Route (Login)
r.Get("/signin", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Login Page"))
})
// Protected Route
r.Get("/dashboard", func(w http.ResponseWriter, r *http.Request) {
// Retrieve the authenticated user
user, err := auth.GetSessionUser(r.Context())
if err != nil {
http.Redirect(w, r, "/signin", http.StatusSeeOther)
return
}
w.Write([]byte(fmt.Sprintf("Welcome, %s!", user.Email)))
})
fmt.Println("Server starting on :3000")
http.ListenAndServe(":3000", r)
}
[!TIP] Besides
auth.Migrate(), theEzAuthinstance also exposes two rollback helpers for library users:auth.MigrateDown()rolls back every migration (empty schema), andauth.MigrateRevert()rolls back only the single most recently applied one.
Core Components
When you initialize ezauth, you get access to several key components through the EzAuth struct:
EzAuth Struct
The EzAuth struct is the main entry point. It contains:
- Config: The loaded configuration.
- Repo: The database repository.
- Service: The core authentication logic.
- Handler: The HTTP handler.
The Handler
The Handler (accessible via auth.Handler) handles all HTTP routing and request processing. It is built on top of chi, but it implements the http.Handler interface, so it can be used with any Go HTTP framework.
Key methods:
- ServeHTTP(w, r): Standard HTTP handler method.
- AuthMiddleware(next): Middleware to protect routes. It validates the JWT in the Authorization header and puts the userID in the request context.
The Service
The Service (accessible via auth.Service) contains the business logic for authentication. You can use it directly if you want to perform actions programmatically without going through HTTP.
Example of using the service directly:
// Create a user manually
user, err := auth.Service.UserCreate(ctx, &service.RequestBasicAuth{
Email: "user@example.com",
Password: "securepassword",
})
// Generate tokens for a user
tokens, err := auth.Service.TokenCreate(ctx, user)
Where to Go Next
- Sessions, Middleware and Helpers: cookie sessions, route protection, CSRF, and the package-level helper functions.
- Account Security: MFA, trusted devices, session revocation, refresh-token reuse detection, scoped API keys.
- Admin and Operations: impersonation, roles & permissions (RBAC), organizations (multi-tenancy), invitations, admin user management, audit log, hooks.
- Configuration: every environment variable.
- API Endpoints: the full endpoint reference.
Using an Existing Database Connection
If your application already has a *sql.DB connection, you can use NewWithDB:
auth, err := ezauth.NewWithDB(&cfg, myDBConnection, "auth")
NewWithDB applies ezauth's default connection pool limits (25 max open, 5
max idle, 30 minute max lifetime) to myDBConnection, overwriting whatever it
was configured with. If you need different limits, call
myDBConnection.SetMaxOpenConns / SetMaxIdleConns / SetConnMaxLifetime
after NewWithDB returns -- they take effect immediately on the same
connection pool.