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.
go get github.com/midsbie/authagonMinimal 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.
- 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
commonAzure AD endpoint andUser.Readscope. oauth2.WithTenant("organizations")to target a specific tenant.oauth2.WithMicrosoftScopes(...)andoauth2.WithMicrosoftCallbackURL(...)for overrides.
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).
- Redirect URLs:
- All post-login redirects are normalized via a
RedirectValidator(defaults toSanitizeRedirectURL). - Only same-site, relative paths are allowed; invalid values fall back to
"/".
- All post-login redirects are normalized via a
- Audience:
JWTStateStorecan enforce an audience viaWithAudience; mismatches are rejected.- Expired handshake tokens surface as
ErrTokenExpired.
- Cookies:
CookieStoredefaults 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:
SessionCtlis an optional, batteries-included helper that storesAuthResultin aSessionStorer[AuthResult]behind a browser cookie.- Applications with existing session infrastructure can ignore
SessionCtland manage app sessions directly; see examples/oauth2-core-flow for a minimal example.
Authagon is released under the MIT License. See LICENSE for details.