Authsome

Getting Started

Install Authsome and run your first auth flow in five minutes.

This guide walks you through installing Authsome, creating an engine with password authentication, starting a local server, and exercising the sign-up, sign-in, and session endpoints with curl. By the end you will have a working auth service you can extend with additional plugins.

Prerequisites

  • Go 1.24 or later — the module requires recent generics and log/slog support
  • A Go module (go mod init your/module)
  • curl or any HTTP client for testing

Install

go get github.com/xraph/authsome

This installs the core engine, all built-in plugins, and the store/memory backend. Add a database-backed store separately when needed:

# PostgreSQL
go get github.com/xraph/authsome/store/postgres

# SQLite
go get github.com/xraph/authsome/store/sqlite

# MongoDB
go get github.com/xraph/authsome/store/mongo

Step 1 — Create the engine

Create a main.go file. Start with the in-memory store so you can run immediately without a database.

package main

import (
    "context"
    "log"
    "log/slog"
    "net/http"
    "time"

    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/password"
    "github.com/xraph/authsome/store/memory"
)

func main() {
    ctx := context.Background()

    // In-memory store is perfect for local development.
    // Swap for postgres.New() or sqlite.New() before deploying.
    memStore := memory.New()

    eng, err := authsome.New(
        authsome.WithStore(memStore),
        authsome.WithLogger(slog.Default()),
        authsome.WithPlugin(password.New()),
        authsome.WithConfig(authsome.Config{
            AppID:    "myapp",
            BasePath: "/v1/auth",
            Session: authsome.SessionConfig{
                TokenTTL:        1 * time.Hour,
                RefreshTokenTTL: 30 * 24 * time.Hour,
            },
            Password: authsome.PasswordConfig{
                MinLength:        8,
                RequireUppercase: true,
                RequireLowercase: true,
                RequireDigit:     true,
            },
        }),
    )
    if err != nil {
        log.Fatal(err)
    }

The password.New() call registers the password strategy and contributes the /signup, /signin, /forgot-password, /reset-password, and /change-password route handlers.

Step 2 — Start the engine

Start runs schema migrations and calls OnInit on every registered plugin. Always call Stop to flush in-flight operations on shutdown.

    if err := eng.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer eng.Stop(ctx)

When using the memory store, Start is a no-op for migrations since there is no schema to apply. With postgres or sqlite, Start runs embedded SQL migrations automatically unless WithDisableMigrate() is passed.

Step 3 — Register API routes

Authsome auto-registers all plugin-contributed routes on any http.ServeMux. Call RegisterRoutes after Start.

    mux := http.NewServeMux()
    eng.RegisterRoutes(mux)

    log.Println("listening on :8080")
    if err := http.ListenAndServe(":8080", mux); err != nil {
        log.Fatal(err)
    }
}

Your application now serves the following endpoints under /v1/auth:

MethodPathDescription
POST/v1/auth/signupCreate account and return session
POST/v1/auth/signinSign in with email + password
POST/v1/auth/signoutRevoke the current session
POST/v1/auth/refreshExchange refresh token for new tokens
GET/v1/auth/meReturn the currently authenticated user
POST/v1/auth/forgot-passwordRequest a password reset email
POST/v1/auth/reset-passwordConfirm reset with token + new password
POST/v1/auth/change-passwordChange password (requires current password)

Step 4 — Test with curl

Run the server (go run .), then exercise the endpoints.

Sign up

curl -s -X POST http://localhost:8080/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"Secure1234","app_id":"myapp"}' | jq .

Response:

{
  "user": {
    "id": "ausr_01j9...",
    "email": "alice@example.com",
    "app_id": "aapp_01j9...",
    "created_at": "2024-11-01T10:00:00Z"
  },
  "session": {
    "id": "ases_01j9...",
    "token": "a3f8c9d4...",
    "refresh_token": "d72b1ef8...",
    "expires_at": "2024-11-01T11:00:00Z"
  }
}

Sign in

TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"Secure1234","app_id":"myapp"}' \
  | jq -r '.session.token')

Call the /me endpoint

curl -s http://localhost:8080/v1/auth/me \
  -H "Authorization: Bearer $TOKEN" | jq .

Response:

{
  "id": "ausr_01j9...",
  "email": "alice@example.com",
  "email_verified": false,
  "app_id": "aapp_01j9...",
  "created_at": "2024-11-01T10:00:00Z",
  "updated_at": "2024-11-01T10:00:00Z"
}

Refresh tokens

REFRESH=$(curl -s -X POST http://localhost:8080/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"Secure1234","app_id":"myapp"}' \
  | jq -r '.session.refresh_token')

curl -s -X POST http://localhost:8080/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d "{\"refresh_token\":\"$REFRESH\"}" | jq .

The response includes a new token and, if refresh token rotation is enabled (the default), a new refresh_token. The old refresh token is immediately invalidated.

Step 5 — Add more plugins

The real power of Authsome is in its plugin system. Add plugins at engine construction time.

import "github.com/xraph/authsome/plugins/magiclink"

eng, err := authsome.New(
    authsome.WithStore(memStore),
    authsome.WithPlugin(password.New()),
    authsome.WithPlugin(magiclink.New(magiclink.Config{
        TokenTTL: 15 * time.Minute,
    })),
    // A mailer bridge is required to deliver magic link emails.
    authsome.WithMailer(myMailer),
)

Add Google and GitHub social login

import "github.com/xraph/authsome/plugins/social"

eng, err := authsome.New(
    authsome.WithStore(memStore),
    authsome.WithPlugin(password.New()),
    authsome.WithPlugin(social.New(social.Config{
        Providers: []social.Provider{
            {
                Name:         "google",
                ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
                ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
                RedirectURL:  "https://myapp.com/v1/auth/social/google/callback",
            },
            {
                Name:         "github",
                ClientID:     os.Getenv("GITHUB_CLIENT_ID"),
                ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
                RedirectURL:  "https://myapp.com/v1/auth/social/github/callback",
            },
        },
    })),
)

Add TOTP-based MFA

import "github.com/xraph/authsome/plugins/mfa"

eng, err := authsome.New(
    authsome.WithStore(memStore),
    authsome.WithPlugin(password.New()),
    authsome.WithPlugin(mfa.New(mfa.Config{
        TOTPIssuer: "MyApp",
    })),
)

Step 6 — Switch to PostgreSQL

When you are ready for a persistent store, swap the backend. The engine API does not change.

import "github.com/xraph/authsome/store/postgres"

pgStore, err := postgres.New(ctx, "postgres://user:pass@localhost:5432/myapp_auth")
if err != nil {
    log.Fatal(err)
}

eng, err := authsome.New(
    authsome.WithStore(pgStore),
    // ... same plugins and config
)

Start will apply all pending schema migrations automatically. Existing data is preserved across upgrades.

For production deployments, run migrations in a dedicated step rather than relying on auto-migration at startup. Pass WithDisableMigrate() to the engine and invoke eng.Migrate(ctx) from your deployment pipeline before starting the server.

Next steps

On this page