Skip to content

midsbie/authagon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

104 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Authagon

Overview

Authagon is a small Go library for OAuth2/OIDC login flows. It provides:

  • Infrastructure for browser and session storage.
  • OAuth2 service orchestration and provider abstraction.
  • A clear split between handshake state and long-lived app sessions.

Targets Go developers building web apps that delegate authentication to providers like Google and Microsoft.

Installation

go get github.com/midsbie/authagon

Quick Start

Minimal wiring for a web app (error handling omitted for brevity):

import (
    "fmt"
    "net/http"

    "github.com/midsbie/authagon/oauth2"
    "github.com/midsbie/authagon/store"
)

func main() {
    // Browser + handshake state
    cookieStore := store.NewCookieStore(store.WithSecure(false)) // HTTPS-only in production
    jwtState, _ := oauth2.NewJWTStateStore(cookieStore, "your-session-secret")

    // OAuth2 service (single Google provider for brevity)
    svc, _ := oauth2.NewService(jwtState,
        oauth2.WithBaseURL("http://localhost:3000"))
    svc.Register(oauth2.NewGoogle("google-client-id", "google-client-secret"))

    // App sessions (AuthResult)
    sessionStore := store.NewMemoryStore[oauth2.AuthResult]()
    sessionCtl := oauth2.NewSessionCtl(cookieStore, sessionStore)

    // Start the OAuth2 login flow.
    http.HandleFunc("/u/auth/google", func(w http.ResponseWriter, r *http.Request) {
        auth, _ := svc.NewAuthenticator("google")
        _ = auth.Start(w, r, oauth2.AuthConfig{
            RedirectURL: "/u/profile",
        })
    })

    // Handle the OAuth2 callback, create an app session, and redirect.
    http.HandleFunc("/u/auth/google/callback", func(w http.ResponseWriter, r *http.Request) {
        auth, _ := svc.NewAuthenticator("google")
        result, _ := auth.Complete(w, r)
        _, _ = sessionCtl.Set(r.Context(), w, *result)
        http.Redirect(w, r, result.RedirectURL, http.StatusFound)
    })

    // Example authenticated endpoint.
    http.HandleFunc("/u/profile", func(w http.ResponseWriter, r *http.Request) {
        sess, ok, _ := sessionCtl.Get(r.Context(), r)
        if !ok {
            http.Error(w, "Not authenticated", http.StatusUnauthorized)
            return
        }
        fmt.Fprintf(w, "Hello, %s!", sess.Profile.Name)
    })

    http.ListenAndServe(":3000", nil)
}

For a full working app that uses SessionCtl, see examples/oauth2-web-starter. For an example where the application manages its own sessions without SessionCtl, see examples/oauth2-core-flow.

Providers

Built-in

  • Google:
    • oauth2.NewGoogle(clientID, clientSecret, opts...)
    • Uses Google OAuth2 endpoints and a default profile scope set.
  • Microsoft:
    • oauth2.NewMicrosoft(clientID, clientSecret, opts...)
    • Defaults to the common Azure AD endpoint and User.Read scope.
    • oauth2.WithTenant("organizations") to target a specific tenant.
    • oauth2.WithMicrosoftScopes(...) and oauth2.WithMicrosoftCallbackURL(...) for overrides.

Custom Providers

Use specs and configs directly:

import (
    xoauth2 "golang.org/x/oauth2"

    "github.com/midsbie/authagon/oauth2"
)

spec := oauth2.ProviderSpec{
    ID: "acme",
    Endpoints: oauth2.ProviderEndpoints{
        OAuth2: xoauth2.Endpoint{
            AuthURL:  "https://idp.example/auth",
            TokenURL: "https://idp.example/token",
        },
        ProfileURL: "https://idp.example/me",
    },
    DefaultScopes: []string{"openid", "profile"},
    ExtractProfile: func(m oauth2.ProfileMap, _ []byte) (oauth2.Profile, error) {
        return oauth2.Profile{ID: m.String("id"), Name: m.String("name")}, nil
    },
}

cfg := oauth2.ProviderConfig{ClientID: "id", ClientSecret: "secret"}
prov := oauth2.NewProvider(spec, cfg)

Register with OAuth2Service.Register(prov).

Additional Notes

  • Redirect URLs:
    • All post-login redirects are normalized via a RedirectValidator (defaults to SanitizeRedirectURL).
    • Only same-site, relative paths are allowed; invalid values fall back to "/".
  • Audience:
    • JWTStateStore can enforce an audience via WithAudience; mismatches are rejected.
    • Expired handshake tokens surface as ErrTokenExpired.
  • Cookies:
    • CookieStore defaults to production-safe settings:
      • Secure=true, HttpOnly=true, SameSiteDefaultMode, path "/".
    • For local HTTP development you can set store.WithSecure(false); do not do this in production.
  • Sessions:
    • SessionCtl is an optional, batteries-included helper that stores AuthResult in a SessionStorer[AuthResult] behind a browser cookie.
    • Applications with existing session infrastructure can ignore SessionCtl and manage app sessions directly; see examples/oauth2-core-flow for a minimal example.

License

Authagon is released under the MIT License. See LICENSE for details.

About

Go library for OAuth2/OIDC login flows with clear separation between handshake state and app sessions

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages