Skip to content

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(), the EzAuth instance also exposes two rollback helpers for library users: auth.MigrateDown() rolls back every migration (empty schema), and auth.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

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.