Marketplace

goth-fundamentals

This skill should be used when the user asks to "set up goth", "install goth", "oauth in go", "authentication in golang", "goth package", "goth basics", or mentions "github.com/markbates/goth". Provides foundational guidance for the Goth multi-provider authentication library.

$ 安裝

git clone https://github.com/linehaul-ai/linehaulai-claude-marketplace /tmp/linehaulai-claude-marketplace && cp -r /tmp/linehaulai-claude-marketplace/plugins/goth-oauth/skills/goth-fundamentals ~/.claude/skills/linehaulai-claude-marketplace

// tip: Run this command in your terminal to install the skill


name: goth-fundamentals description: This skill should be used when the user asks to "set up goth", "install goth", "oauth in go", "authentication in golang", "goth package", "goth basics", or mentions "github.com/markbates/goth". Provides foundational guidance for the Goth multi-provider authentication library.

Goth Fundamentals

Expert guidance for github.com/markbates/goth - a Go library providing simple, clean, idiomatic multi-provider OAuth authentication.

Installation

Install the package:

go get github.com/markbates/goth

Import in code:

import (
    "github.com/markbates/goth"
    "github.com/markbates/goth/gothic"
    "github.com/markbates/goth/providers/google"
)

Core Concepts

Provider Interface

Every authentication provider implements the goth.Provider interface:

type Provider interface {
    Name() string
    BeginAuth(state string) (Session, error)
    UnmarshalSession(string) (Session, error)
    FetchUser(Session) (User, error)
    Debug(bool)
    RefreshToken(refreshToken string) (*oauth2.Token, error)
    RefreshTokenAvailable() bool
}

Key methods:

  • Name() - Returns provider identifier (e.g., "google", "microsoft")
  • BeginAuth() - Initiates OAuth flow, returns session with auth URL
  • FetchUser() - Retrieves user data after successful authentication
  • RefreshToken() - Obtains new access token using refresh token

Session Interface

Sessions manage OAuth state throughout the authentication flow:

type Session interface {
    GetAuthURL() (string, error)
    Authorize(Provider, Params) (string, error)
    Marshal() string
}

User Struct

Authenticated user data returned after successful OAuth:

type User struct {
    RawData           map[string]interface{}
    Provider          string
    Email             string
    Name              string
    FirstName         string
    LastName          string
    NickName          string
    Description       string
    UserID            string
    AvatarURL         string
    Location          string
    AccessToken       string
    AccessTokenSecret string
    RefreshToken      string
    ExpiresAt         time.Time
    IDToken           string
}

Gothic Helper Package

The gothic package provides convenience functions for common web frameworks:

Key Functions

// Begin authentication - redirects to provider
gothic.BeginAuthHandler(res http.ResponseWriter, req *http.Request)

// Complete authentication - handles callback
gothic.CompleteUserAuth(res http.ResponseWriter, req *http.Request) (goth.User, error)

// Get user from session (if already authenticated)
gothic.GetFromSession(providerName string, req *http.Request) (string, error)

// Logout user
gothic.Logout(res http.ResponseWriter, req *http.Request) error

Provider Selection

Gothic uses the provider query parameter or URL path segment to identify which provider to use:

// Query parameter: /auth?provider=google
// Path segment: /auth/google

Override the provider getter if needed:

gothic.GetProviderName = func(req *http.Request) (string, error) {
    return mux.Vars(req)["provider"], nil
}

Basic Authentication Flow

Step 1: Register Providers

Initialize providers at application startup:

func init() {
    goth.UseProviders(
        google.New(
            os.Getenv("GOOGLE_CLIENT_ID"),
            os.Getenv("GOOGLE_CLIENT_SECRET"),
            "http://localhost:3000/auth/google/callback",
            "email", "profile",
        ),
    )
}

Step 2: Create Auth Routes

func main() {
    http.HandleFunc("/auth/", handleAuth)
    http.HandleFunc("/auth/callback/", handleCallback)
    http.HandleFunc("/logout", handleLogout)
    http.ListenAndServe(":3000", nil)
}

func handleAuth(w http.ResponseWriter, r *http.Request) {
    gothic.BeginAuthHandler(w, r)
}

func handleCallback(w http.ResponseWriter, r *http.Request) {
    user, err := gothic.CompleteUserAuth(w, r)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    // User authenticated - store in session, redirect, etc.
    fmt.Fprintf(w, "Welcome %s!", user.Name)
}

func handleLogout(w http.ResponseWriter, r *http.Request) {
    gothic.Logout(w, r)
    http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}

Step 3: Configure Session Store

Gothic uses gorilla/sessions by default:

import "github.com/gorilla/sessions"

func init() {
    key := os.Getenv("SESSION_SECRET")
    maxAge := 86400 * 30 // 30 days
    isProd := os.Getenv("ENV") == "production"

    store := sessions.NewCookieStore([]byte(key))
    store.MaxAge(maxAge)
    store.Options.Path = "/"
    store.Options.HttpOnly = true
    store.Options.Secure = isProd

    gothic.Store = store
}

Environment Variables Pattern

Store OAuth credentials securely using environment variables:

# .env (never commit this file)
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
MICROSOFT_CLIENT_ID=your-azure-app-id
MICROSOFT_CLIENT_SECRET=your-azure-secret
SESSION_SECRET=your-32-byte-random-string

Load with godotenv or similar:

import "github.com/joho/godotenv"

func init() {
    godotenv.Load()
}

Supported Providers (70+)

Goth includes providers for major platforms:

CategoryProviders
Cloud/EnterpriseGoogle, Microsoft (Azure AD), Apple, Amazon, Okta, Auth0
DevelopmentGitHub, GitLab, Bitbucket, Gitea
SocialFacebook, Twitter, Instagram, LinkedIn, Discord
ProductivitySlack, Salesforce, Shopify, Zoom
OtherSpotify, Twitch, PayPal, Stripe, Uber

Import provider packages individually:

import (
    "github.com/markbates/goth/providers/google"
    "github.com/markbates/goth/providers/azureadv2"
    "github.com/markbates/goth/providers/github"
)

Error Handling

Handle common authentication errors:

user, err := gothic.CompleteUserAuth(w, r)
if err != nil {
    switch {
    case strings.Contains(err.Error(), "access_denied"):
        // User denied access
        http.Redirect(w, r, "/login?error=denied", http.StatusTemporaryRedirect)
    case strings.Contains(err.Error(), "invalid_grant"):
        // Token expired or revoked
        http.Redirect(w, r, "/login?error=expired", http.StatusTemporaryRedirect)
    default:
        // Log and show generic error
        log.Printf("Auth error: %v", err)
        http.Error(w, "Authentication failed", http.StatusInternalServerError)
    }
    return
}

Token Refresh

For long-lived sessions, refresh tokens before expiry:

func refreshIfNeeded(provider goth.Provider, user *goth.User) error {
    if !provider.RefreshTokenAvailable() {
        return nil
    }

    if time.Until(user.ExpiresAt) > 5*time.Minute {
        return nil // Token still valid
    }

    token, err := provider.RefreshToken(user.RefreshToken)
    if err != nil {
        return err
    }

    user.AccessToken = token.AccessToken
    user.RefreshToken = token.RefreshToken
    user.ExpiresAt = token.Expiry
    return nil
}

Quick Reference

TaskFunction/Pattern
Register providersgoth.UseProviders(provider1, provider2)
Start auth flowgothic.BeginAuthHandler(w, r)
Complete authgothic.CompleteUserAuth(w, r)
Logoutgothic.Logout(w, r)
Get current providergothic.GetProviderName(r)
Configure session storegothic.Store = yourStore
Access user datauser.Email, user.Name, user.AccessToken

Related Skills

  • goth-providers - Detailed provider configuration (Google, Microsoft)
  • goth-echo-security - Echo framework integration and security patterns

References

Repository

linehaul-ai
linehaul-ai
Author
linehaul-ai/linehaulai-claude-marketplace/plugins/goth-oauth/skills/goth-fundamentals
1
Stars
0
Forks
Updated4d ago
Added1w ago