Documentation
¶
Overview ¶
Package federatedauth owns provider-mediated authentication orchestration — OAuth and SAML callback handlers plus account-linking helpers — that build on the account model in accounts/ and the session/middleware machinery in httpauth/.
Index ¶
- type AuthUserStore
- type EnsureAuthUserConfig
- type EnsureAuthUserFunc
- type OAuthBridge
- func (b *OAuthBridge) GetLinkingUserID(r *http.Request) string
- func (b *OAuthBridge) HandleLinkOAuthCallback(linkingUserID, provider string, userInfo map[string]any, w http.ResponseWriter, ...)
- func (b *OAuthBridge) SaveUserAndRedirect(authtype, provider string, token *oauth2.Token, userInfo map[string]any, ...)
- func (b *OAuthBridge) StartLinkOAuth(r *http.Request, userID string)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthUserStore ¶
type AuthUserStore interface {
accounts.UserStore
accounts.IdentityStore
accounts.ChannelStore
// EnsureAuthUser orchestrates user creation/lookup across stores.
// This is the main entry point for OAuth and local authentication.
EnsureAuthUser(authtype string, provider string, token *oauth2.Token, userInfo map[string]any) (accounts.User, error)
}
AuthUserStore combines the store interfaces needed for federated-auth callbacks plus the EnsureAuthUser orchestration that turns provider userInfo into an accounts.User.
type EnsureAuthUserConfig ¶
type EnsureAuthUserConfig struct {
UserStore accounts.UserStore
IdentityStore accounts.IdentityStore
ChannelStore accounts.ChannelStore
UsernameStore accounts.UsernameStore
}
EnsureAuthUserConfig holds configuration for NewEnsureAuthUserFunc.
type EnsureAuthUserFunc ¶
type EnsureAuthUserFunc func(authtype string, provider string, token any, userInfo map[string]any) (accounts.User, error)
EnsureAuthUserFunc handles user creation/lookup for both OAuth and local authentication with channel linking support.
func NewEnsureAuthUserFunc ¶
func NewEnsureAuthUserFunc(config EnsureAuthUserConfig) EnsureAuthUserFunc
NewEnsureAuthUserFunc creates a function that handles user creation/lookup for both OAuth and local authentication with channel linking support.
type OAuthBridge ¶
type OAuthBridge struct {
OneAuth *httpauth.OneAuth
UserStore AuthUserStore
}
OAuthBridge wires httpauth's session/cookie machinery to the federated-auth callback flow. Construct one per OneAuth instance and hand its methods to your OAuth provider handlers.
Example:
bridge := federatedauth.NewOAuthBridge(oneauth, authUserStore)
oneauth.AddAuth("/google", oa2.NewGoogleOAuth2(
clientID, clientSecret, callbackURL,
bridge.SaveUserAndRedirect,
).Handler())
func NewOAuthBridge ¶
func NewOAuthBridge(oneAuth *httpauth.OneAuth, userStore AuthUserStore) *OAuthBridge
NewOAuthBridge creates an OAuthBridge that callbacks dispatch through.
func (*OAuthBridge) GetLinkingUserID ¶
func (b *OAuthBridge) GetLinkingUserID(r *http.Request) string
GetLinkingUserID retrieves and clears the linking user ID from session. Call this in your OAuth callback to detect linking mode.
func (*OAuthBridge) HandleLinkOAuthCallback ¶
func (b *OAuthBridge) HandleLinkOAuthCallback(linkingUserID, provider string, userInfo map[string]any, w http.ResponseWriter, r *http.Request)
HandleLinkOAuthCallback links an OAuth provider channel onto an existing, already-logged-in user.
Who Calls This ¶
This is called by OAuth providers after the user authorizes linking. The flow is:
- Local-only user visits profile, clicks "Link Google Account"
- App stores user ID in session as "linkingUserID" (via b.StartLinkOAuth)
- App redirects to Google OAuth with special state
- Google redirects back to /auth/google/callback
- OAuth callback sees "linkingUserID" in session (via b.GetLinkingUserID)
- Instead of normal login, calls this handler to link the account
How to Set Up ¶
Modify your OAuth callback to detect linking mode:
func googleCallback(w http.ResponseWriter, r *http.Request) {
// ... exchange code for token, get userInfo ...
linkingUserID := bridge.GetLinkingUserID(r)
if linkingUserID != "" {
bridge.HandleLinkOAuthCallback(linkingUserID, "google", userInfo, w, r)
return
}
bridge.SaveUserAndRedirect("oauth", "google", token, userInfo, w, r)
}
What It Does ¶
- Verifies the OAuth email matches the user's existing email identity
- Creates OAuth channel for the provider
- Updates user profile["channels"] to include the new provider
- Redirects to callback URL
Security ¶
The OAuth email MUST match the user's existing email to prevent account hijacking. Users cannot link to a different email address.
func (*OAuthBridge) SaveUserAndRedirect ¶
func (b *OAuthBridge) SaveUserAndRedirect(authtype, provider string, token *oauth2.Token, userInfo map[string]any, w http.ResponseWriter, r *http.Request)
SaveUserAndRedirect is called by an OAuth callback handler with the auth token and user info after a successful auth flow and redirect.
Here is our opportunity to:
- Create a userId that is unique to our system based on userInfo
- Set the right session cookies from this
func (*OAuthBridge) StartLinkOAuth ¶
func (b *OAuthBridge) StartLinkOAuth(r *http.Request, userID string)
StartLinkOAuth initiates OAuth account linking by storing the user ID in session. Call this from your "Link [Provider] Account" button handler.
Example:
func handleLinkGoogle(w http.ResponseWriter, r *http.Request) {
userID := getLoggedInUserID(r)
bridge.StartLinkOAuth(r, userID)
http.Redirect(w, r, "/auth/google/", http.StatusFound)
}