Plugin Architecture
How Authsome's plugin system extends the engine with authentication strategies, hooks, routes, and migrations.
Authsome is built around a composable plugin architecture. Every authentication method, lifecycle behavior, and integration point is implemented as a plugin that registers itself with the engine. The core engine provides session management, user storage, and the hook bus -- plugins add everything else.
The Plugin interface
Every plugin must implement the base Plugin interface:
type Plugin interface {
Name() string
}The Name() method returns a unique identifier used for logging, debugging, and registry deduplication. Beyond this single required method, plugins opt into capabilities by implementing additional interfaces.
Capability interfaces
Plugins declare what they can do by implementing zero or more of the following interfaces:
| Interface | Purpose |
|---|---|
OnInit | Called during engine.Start() to capture engine references |
OnShutdown | Called during graceful shutdown |
RouteProvider | Registers additional HTTP routes on the Forge router |
MigrationProvider | Contributes database migration groups for plugin tables |
StrategyProvider | Contributes an authentication strategy to the strategy registry |
AuthMethodContributor | Reports which auth methods are linked to a user |
AuthMethodUnlinker | Supports unlinking an auth method from a user account |
DataExportContributor | Contributes data to GDPR user exports |
Extensible | Accepts sub-plugins for compositional plugin design |
Hook interfaces
Plugins can subscribe to lifecycle events by implementing hook interfaces. Before-hooks can abort the operation by returning an error. After-hooks are fire-and-forget -- errors are logged but never block the pipeline.
Auth event hooks
| Interface | Trigger |
|---|---|
BeforeSignUp / AfterSignUp | User account creation |
BeforeSignIn / AfterSignIn | Authentication attempt |
BeforeSignOut / AfterSignOut | Session termination |
User lifecycle hooks
| Interface | Trigger |
|---|---|
BeforeUserCreate / AfterUserCreate | User record creation |
BeforeUserUpdate / AfterUserUpdate | User record update |
BeforeUserDelete / AfterUserDelete | User record deletion |
Session lifecycle hooks
| Interface | Trigger |
|---|---|
BeforeSessionCreate / AfterSessionCreate | Session creation |
AfterSessionRefresh | Token refresh |
AfterSessionRevoke | Session revocation |
Organization lifecycle hooks
| Interface | Trigger |
|---|---|
AfterOrgCreate / AfterOrgUpdate / AfterOrgDelete | Organization CRUD |
AfterMemberAdd / AfterMemberRemove / AfterMemberRoleChange | Membership changes |
Plugin registry
The plugin.Registry is the core dispatch mechanism. It type-caches plugins at registration time so that emit calls iterate only over plugins implementing the relevant hook -- there is no runtime type assertion on the hot path.
registry := plugin.NewRegistry(logger)
registry.Register(passwordPlugin)
registry.Register(mfaPlugin)
registry.Register(socialPlugin)
// During sign-up, only plugins implementing BeforeSignUp are called:
err := registry.EmitBeforeSignUp(ctx, req)Lifecycle
When you call engine.Start(), the following sequence executes:
- Registration -- Plugins passed via
WithPlugin()are registered with the plugin registry. Each plugin is type-asserted into all applicable hook caches. - Migration -- The engine collects migration groups from all
MigrationProviderplugins and runs them alongside core schema migrations. - Initialization -- The registry calls
OnInit(ctx, engine)on every plugin that implementsOnInit. Plugins use this to capture store references, bridge handles, and other engine capabilities. - Strategy registration -- Plugins implementing
StrategyProviderhave their strategies auto-registered with the strategy registry. - Route registration -- Plugins implementing
RouteProviderhave their HTTP routes registered on the Forge router.
Built-in plugins
Authsome ships with 14 built-in plugins:
| Plugin | Package | Description |
|---|---|---|
password | plugins/password | Email/password sign-up and sign-in with bcrypt or argon2id hashing |
email | plugins/email | Email notifications for welcome, verification, and password reset |
magiclink | plugins/magiclink | Passwordless authentication via emailed magic links |
mfa | plugins/mfa | Multi-factor authentication with TOTP, SMS OTP, and recovery codes |
passkey | plugins/passkey | FIDO2/WebAuthn passkey registration and authentication |
social | plugins/social | OAuth2 social login (Google, GitHub, Microsoft, Apple, custom) |
sso | plugins/sso | Enterprise SSO via OIDC and SAML |
oauth2provider | plugins/oauth2provider | OAuth2 authorization server (Authorization Code + PKCE, Client Credentials) |
organization | plugins/organization | Organization, member, and team management with invitations |
consent | plugins/consent | GDPR consent tracking with grant, revoke, and audit trail |
phone | plugins/phone | Phone number verification and OTP-based authentication |
notification | plugins/notification | Multi-channel notifications via Herald bridge |
apikey | plugins/apikey | API key generation, scoping, rotation, and authentication strategy |
device | device | Device fingerprinting, trust management, and session binding |
Example: registering plugins
import (
"github.com/xraph/authsome"
"github.com/xraph/authsome/plugins/password"
"github.com/xraph/authsome/plugins/mfa"
"github.com/xraph/authsome/plugins/social"
)
eng, err := authsome.NewEngine(
authsome.WithStore(store),
authsome.WithPlugin(password.New()),
authsome.WithPlugin(mfa.New(mfa.Config{Issuer: "MyApp"})),
authsome.WithPlugin(social.New(social.Config{
Providers: []social.Provider{
social.NewGoogle(googleCfg),
social.NewGitHub(githubCfg),
},
})),
)Plugins are initialized in registration order. If plugin B depends on state set by plugin A during OnInit, register A first.