### Run Goth Examples Source: https://github.com/markbates/goth/blob/master/README.md Follow these steps to set up and run the Goth example application. Ensure you have the necessary dependencies installed and then build and execute the example. ```text $ cd goth/examples $ go get -v $ go build $ ./examples ``` -------------------------------- ### Install Goth Package Source: https://github.com/markbates/goth/blob/master/README.md Use this command to get the Goth package for your Go project. ```text $ go get github.com/markbates/goth ``` -------------------------------- ### Run Goth Nextcloud Login Example Source: https://github.com/markbates/goth/blob/master/providers/nextcloud/README.md Execute the Goth example application for Nextcloud login. Requires Nextcloud URL, client key, client secret, and a session secret. The example application is located at /examples. ```bash NEXTCLOUD_URL=https://goth.my.server.name \ NEXTCLOUD_KEY= \ NEXTCLOUD_SECRET= \ SESSION_SECRET=1 \ ./examples ``` -------------------------------- ### Install Goth using Go Modules Source: https://context7.com/markbates/goth/llms.txt Install the Goth library to add multi-provider authentication to your Go application. ```bash go get github.com/markbates/goth ``` -------------------------------- ### Complete Application Example with Multiple Providers in Go Source: https://context7.com/markbates/goth/llms.txt A full working example demonstrating multi-provider authentication with session handling, error handling, and user display using the gorilla/pat router. Ensure you set the SESSION_SECRET environment variable. ```go package main import ( "fmt" "html/template" "log" "net/http" "os" "sort" "github.com/gorilla/pat" "github.com/gorilla/sessions" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/github" "github.com/markbates/goth/providers/google" "github.com/markbates/goth/providers/discord" ) func main() { // Configure secure session store store := sessions.NewCookieStore([]byte(os.Getenv("SESSION_SECRET"))) store.MaxAge(86400 * 30) store.Options.HttpOnly = true store.Options.Secure = os.Getenv("ENV") == "production" gothic.Store = store // Register providers goth.UseProviders( google.New(os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback"), github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"), discord.New(os.Getenv("DISCORD_KEY"), os.Getenv("DISCORD_SECRET"), "http://localhost:3000/auth/discord/callback", discord.ScopeIdentify, discord.ScopeEmail), ) // Available providers for index page providerList := []string{"google", "github", "discord"} sort.Strings(providerList) p := pat.New() // Home page with login links p.Get("/", func(w http.ResponseWriter, r *http.Request) { tmpl := ` Login

Choose a provider:

{{range .}}

Login with {{.}}

{{end}} ` tt, _ := template.New("index").Parse(tmpl) tt.Execute(w, providerList) }) // Start OAuth flow p.Get("/auth/{provider}", func(w http.ResponseWriter, r *http.Request) { // Check if already authenticated if user, err := gothic.CompleteUserAuth(w, r); err == nil { showUser(w, user) return } gothic.BeginAuthHandler(w, r) }) // OAuth callback p.Get("/auth/{provider}/callback", func(w http.ResponseWriter, r *http.Request) { user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, fmt.Sprintf("Authentication failed: %v", err), http.StatusUnauthorized) return } showUser(w, user) }) // Logout p.Get("/logout/{provider}", func(w http.ResponseWriter, r *http.Request) { gothic.Logout(w, r) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) }) log.Println("Server running at http://localhost:3000") log.Fatal(http.ListenAndServe(":3000", p)) } func showUser(w http.ResponseWriter, user goth.User) { tmpl := ` Welcome

Logout

Welcome, {{.Name}}!

  • Provider: {{.Provider}}
  • Email: {{.Email}}
  • UserID: {{.UserID}}
  • NickName: {{.NickName}}
` tt, _ := template.New("user").Parse(tmpl) tt.Execute(w, user) } ``` -------------------------------- ### Start Authentication with BeginAuthHandler Source: https://context7.com/markbates/goth/llms.txt Use gothic.BeginAuthHandler to start the OAuth flow. It extracts the provider name from the request URL and redirects the user to the provider's authentication endpoint. Requires setting up Goth providers. ```go package main import ( "log" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" ) func main() { goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), ) r := mux.NewRouter() // This handler starts the OAuth flow // URL: /auth/google will redirect to Google's consent screen r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler).Methods("GET") log.Println("Server starting on :3000") log.Fatal(http.ListenAndServe(":3000", r)) } ``` -------------------------------- ### Start Nextcloud Docker Container Source: https://github.com/markbates/goth/blob/master/providers/nextcloud/README.md Command to start the Nextcloud Docker container using Docker Compose. Set the NEXTCLOUD_DNS environment variable to your desired domain name. ```bash NEXTCLOUD_DNS=goth.my.server.name docker-compose up -d ``` -------------------------------- ### Configure Session Store in Goth Source: https://github.com/markbates/goth/blob/master/README.md Customize the session store for Goth by overriding the default `gothic.Store`. This example demonstrates how to set session secrets, max age, and security options for production environments. ```go key := "" // Replace with your SESSION_SECRET or similar maxAge := 86400 * 30 // 30 days isProd := false // Set to true when serving over https store := sessions.NewCookieStore([]byte(key)) store.MaxAge(maxAge) store.Options.Path = "/" store.Options.HttpOnly = true // HttpOnly should always be enabled store.Options.Secure = isProd gothic.Store = store ``` -------------------------------- ### Run Goth Provider Test Source: https://github.com/markbates/goth/blob/master/providers/nextcloud/README.md Execute the provider tests for Goth with Nextcloud. Uses the same environment variables as the login example. Ensure you have the Nextcloud URL, client key, and client secret configured. ```bash NEXTCLOUD_URL=https://goth.my.server.name \ NEXTCLOUD_KEY= \ NEXTCLOUD_SECRET= \ SESSION_SECRET=1 \ go test -v ``` -------------------------------- ### Get a Map of All Registered Providers Source: https://context7.com/markbates/goth/llms.txt Get a map of all currently registered providers. Useful for displaying available authentication options or for administrative purposes. ```go package main import ( "fmt" "github.com/markbates/goth" ) func listAvailableProviders() { providers := goth.GetProviders() fmt.Println("Available authentication providers:") for name, provider := range providers { fmt.Printf(" - %s (refresh token: %v)\n", name, provider.RefreshTokenAvailable()) } } ``` -------------------------------- ### Clone Goth Repository Source: https://github.com/markbates/goth/blob/master/README.md Clone the Goth repository from GitHub to access the source code and examples. ```text $ git clone git@github.com:markbates/goth.git ``` -------------------------------- ### Retrieving All Registered Providers Source: https://context7.com/markbates/goth/llms.txt Use `goth.GetProviders` to get a map of all currently registered authentication providers. This is helpful for listing available authentication options or for debugging. ```APIDOC ## goth.GetProviders ### Description Get a map of all currently registered providers. Useful for displaying a list of available authentication options to users or for administrative purposes. ### Method `goth.GetProviders() map[string]goth.Provider` ### Response #### Success Response (200) - **map[string]goth.Provider** - A map where keys are provider names (string) and values are `goth.Provider` interfaces. ### Request Example ```go package main import ( "fmt" "github.com/markbates/goth" ) func listAvailableProviders() { providers := goth.GetProviders() fmt.Println("Available authentication providers:") for name, provider := range providers { fmt.Printf(" - %s (refresh token: %v)\n", name, provider.RefreshTokenAvailable()) } } ``` ``` -------------------------------- ### Configure Google Provider with Custom Options in Go Source: https://context7.com/markbates/goth/llms.txt Customizes the Google OAuth provider by setting specific scopes, forcing account selection, restricting to a Google Workspace domain, and pre-filling the login hint. This example also shows how to access user details and tokens after authentication. ```go package main import ( "fmt" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" ) func main() { // Create Google provider with custom scopes googleProvider := google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", "openid", "email", "profile", // Custom scopes ) // Force account selection on every login googleProvider.SetPrompt("select_account") // Restrict to a specific Google Workspace domain googleProvider.SetHostedDomain("example.com") // Pre-fill the email field googleProvider.SetLoginHint("user@example.com") goth.UseProviders(googleProvider) r := mux.NewRouter() r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", func(w http.ResponseWriter, r *http.Request) { user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Google provides an ID token for additional claims fmt.Printf("ID Token: %s\n", user.IDToken) fmt.Printf("Refresh Token: %s\n", user.RefreshToken) fmt.Printf("Access Token expires at: %s\n", user.ExpiresAt) // Access raw data for additional fields like 'hd' (hosted domain) if hd, ok := user.RawData["hd"]; ok { fmt.Printf("Google Workspace domain: %v\n", hd) } fmt.Fprintf(w, "Welcome, %s!", user.Name) }) http.ListenAndServe(":3000", r) } ``` -------------------------------- ### BeginAuthHandler Source: https://context7.com/markbates/goth/llms.txt A convenience HTTP handler that starts the authentication process. It automatically extracts the provider name from the request URL and redirects the user to the provider's authentication endpoint. ```APIDOC ## GET /auth/{provider} ### Description Starts the OAuth authentication flow for a given provider. This handler automatically extracts the provider name from the URL and redirects the user to the provider's authentication endpoint. ### Method GET ### Endpoint /auth/{provider} ### Parameters #### Path Parameters - **provider** (string) - Required - The name of the authentication provider (e.g., google, github). ### Request Example (No request body for GET requests) ### Response Redirects the user to the OAuth provider's authentication page. ``` -------------------------------- ### Get Authentication URL with GetAuthURL Source: https://context7.com/markbates/goth/llms.txt Use gothic.GetAuthURL to obtain the authentication URL for a provider without redirecting. This is useful for returning the URL to a frontend or for more controlled authentication flows. Requires Goth providers to be configured. ```go package main import ( "encoding/json" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" ) func main() { goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), ) r := mux.NewRouter() // Return auth URL as JSON instead of redirecting r.HandleFunc("/auth/{provider}/url", func(w http.ResponseWriter, r *http.Request) { authURL, err := gothic.GetAuthURL(w, r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "auth_url": authURL, }) }) http.ListenAndServe(":3000", r) } ``` -------------------------------- ### Middleware to Auto-Refresh Expired Tokens Source: https://context7.com/markbates/goth/llms.txt An example middleware function that checks if a user's access token has expired and automatically refreshes it using the stored refresh token if the provider supports it. It updates the user's token and expiry information. ```go // Example: Middleware to auto-refresh expired tokens func refreshTokenMiddleware(user *goth.User) error { if user.ExpiresAt.Before(time.Now()) { provider, err := goth.GetProvider(user.Provider) if err != nil { return err } if provider.RefreshTokenAvailable() && user.RefreshToken != "" { newToken, err := provider.RefreshToken(user.RefreshToken) if err != nil { return err } user.AccessToken = newToken.AccessToken user.ExpiresAt = newToken.Expiry if newToken.RefreshToken != "" { user.RefreshToken = newToken.RefreshToken } } } return nil } ``` -------------------------------- ### Configure Production Session Store in Go Source: https://context7.com/markbates/goth/llms.txt Sets up a secure cookie store for Gothic sessions, suitable for production. Ensure SESSION_SECRET is a 32 or 64-byte key. Configure HttpOnly and Secure flags appropriately for security. ```go package main import ( "os" "github.com/gorilla/sessions" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" ) func main() { // Configure secure session store for production key := os.Getenv("SESSION_SECRET") // Must be 32 or 64 bytes 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 // Prevent JavaScript access store.Options.Secure = isProd // HTTPS only in production store.Options.SameSite = http.SameSiteLaxMode // Override the default Gothic store gothic.Store = store // Now register providers goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), ) } ``` -------------------------------- ### OpenID Connect Authentication with Auto-Discovery Source: https://context7.com/markbates/goth/llms.txt Configure an OpenID Connect provider using its discovery URL. Ensure OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, and OIDC_DISCOVERY_URL environment variables are set. The `SkipUserInfoRequest` flag can be set to true if all necessary claims are present in the ID token. ```go package main import ( "fmt" "log" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/openidConnect" ) func main() { // Create OIDC provider with auto-discovery oidcProvider, err := openidConnect.New( os.Getenv("OIDC_CLIENT_ID"), os.Getenv("OIDC_CLIENT_SECRET"), "http://localhost:3000/auth/openid-connect/callback", os.Getenv("OIDC_DISCOVERY_URL"), // e.g., "https://accounts.google.com/.well-known/openid-configuration" "openid", "email", "profile", ) if err != nil { log.Fatalf("Failed to create OIDC provider: %v", err) } // For multiple OIDC providers, use NewNamed // keycloakProvider, _ := openidConnect.NewNamed( // "keycloak", // Will be named "keycloak-oidc" // os.Getenv("KEYCLOAK_CLIENT_ID"), // os.Getenv("KEYCLOAK_CLIENT_SECRET"), // "http://localhost:3000/auth/keycloak-oidc/callback", // "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration", // ) // Skip UserInfo request if all needed data is in the ID token oidcProvider.SkipUserInfoRequest = true goth.UseProviders(oidcProvider) r := mux.NewRouter() r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", func(w http.ResponseWriter, r *http.Request) { user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Printf("Subject (unique ID): %s\n", user.UserID) fmt.Printf("ID Token: %s\n", user.IDToken) fmt.Printf("Email: %s\n", user.Email) fmt.Fprintf(w, "Authenticated as %s", user.Email) }) http.ListenAndServe(":3000", r) } ``` -------------------------------- ### Registering Authentication Providers Source: https://context7.com/markbates/goth/llms.txt Use `goth.UseProviders` to register one or more authentication providers with Goth. This function can be called multiple times, and duplicate providers will be overwritten by the last instance. Providers must be registered before initiating authentication flows. ```APIDOC ## goth.UseProviders ### Description Register one or more authentication providers with Goth. This function can be called multiple times to add providers, and if the same provider is passed twice, the last instance will be used. Providers must be registered before authentication flows can begin. ### Method `goth.UseProviders` ### Parameters - `providers` ([]goth.Provider) - Required - A slice of `goth.Provider` interfaces to register. ### Request Example ```go package main import ( "github.com/markbates/goth" "github.com/markbates/goth/providers/google" "github.com/markbates/goth/providers/github" "github.com/markbates/goth/providers/facebook" "github.com/markbates/goth/providers/discord" "os" ) func main() { // Register multiple providers at once goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), github.New( os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback", ), facebook.New( os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback", ), discord.New( os.Getenv("DISCORD_KEY"), os.Getenv("DISCORD_SECRET"), "http://localhost:3000/auth/discord/callback", discord.ScopeIdentify, discord.ScopeEmail, ), ) } ``` ### Response This function does not return a value. ``` -------------------------------- ### Register Multiple Authentication Providers Source: https://context7.com/markbates/goth/llms.txt Register one or more authentication providers with Goth. Providers must be registered before authentication flows can begin. If the same provider is passed twice, the last instance will be used. ```go package main import ( "github.com/markbates/goth" "github.com/markbates/goth/providers/google" "github.com/markbates/goth/providers/github" "github.com/markbates/goth/providers/facebook" "github.com/markbates/goth/providers/discord" "os" ) func main() { // Register multiple providers at once goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), github.New( os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback", ), facebook.New( os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback", ), discord.New( os.Getenv("DISCORD_KEY"), os.Getenv("DISCORD_SECRET"), "http://localhost:3000/auth/discord/callback", discord.ScopeIdentify, discord.ScopeEmail, ), ) } ``` -------------------------------- ### Complete User Authentication with CompleteUserAuth Source: https://context7.com/markbates/goth/llms.txt Use gothic.CompleteUserAuth to finish the authentication process and retrieve user information. This function validates the callback, exchanges the code for tokens, and fetches the user's profile, including state validation for CSRF protection. Requires Goth providers to be set up. ```go package main import ( "encoding/json" "fmt" "log" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/github" ) func main() { goth.UseProviders( github.New( os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback", ), ) r := mux.NewRouter() r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", func(w http.ResponseWriter, r *http.Request) { // Complete the auth and get user info user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // User information is now available fmt.Printf("User authenticated!\n") fmt.Printf(" Provider: %s\n", user.Provider) fmt.Printf(" UserID: %s\n", user.UserID) fmt.Printf(" Name: %s\n", user.Name) fmt.Printf(" Email: %s\n", user.Email) fmt.Printf(" AvatarURL: %s\n", user.AvatarURL) // Return user data as JSON w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "id": user.UserID, "name": user.Name, "email": user.Email, "avatar": user.AvatarURL, "provider": user.Provider, }) }) log.Fatal(http.ListenAndServe(":3000", r)) } ``` -------------------------------- ### Goth User Struct Reference Source: https://context7.com/markbates/goth/llms.txt Provides a reference for the goth.User struct, detailing its fields for normalized user information and token details. It includes fields for raw provider data, basic user info, and OAuth tokens. ```go package main import ( "encoding/json" "fmt" "time" "github.com/markbates/goth" ) // goth.User structure reference type UserExample struct { RawData map[string]interface{} // Provider-specific raw data Provider string // Provider name (e.g., "google", "github") Email string Name string FirstName string LastName string NickName string Description string // Bio or about text UserID string // Unique ID from the provider AvatarURL string Location string AccessToken string // OAuth access token AccessTokenSecret string // OAuth 1.0 token secret RefreshToken string // OAuth2 refresh token (if available) ExpiresAt time.Time // Access token expiry IDToken string // OIDC ID token (if available) } func processUser(user goth.User) { // Basic user info available from all providers fmt.Printf("Provider: %s\n", user.Provider) fmt.Printf("User ID: %s\n", user.UserID) fmt.Printf("Email: %s\n", user.Email) fmt.Printf("Name: %s (%s %s)\n", user.Name, user.FirstName, user.LastName) fmt.Printf("Nickname: %s\n", user.NickName) fmt.Printf("Avatar: %s\n", user.AvatarURL) // Token information for API calls fmt.Printf("Access Token: %s...\n", user.AccessToken[:20]) fmt.Printf("Expires: %s\n", user.ExpiresAt) // Access provider-specific raw data if followers, ok := user.RawData["followers"].(float64); ok { fmt.Printf("Followers: %.0f\n", followers) } // Serialize user for storage userData, _ := json.Marshal(user) fmt.Printf("Serialized: %s\n", string(userData)) } ``` -------------------------------- ### Retrieving a Specific Provider Source: https://context7.com/markbates/goth/llms.txt Use `goth.GetProvider` to retrieve a previously registered authentication provider by its name. This is useful for accessing provider-specific methods or verifying its registration. An error is returned if the provider is not found. ```APIDOC ## goth.GetProvider ### Description Retrieve a previously registered provider by name. This is useful for directly accessing a specific provider's methods or checking if a provider has been configured. Returns an error if the provider has not been registered. ### Method `goth.GetProvider(providerName string) (goth.Provider, error)` ### Parameters #### Path Parameters - **providerName** (string) - Required - The name of the provider to retrieve (e.g., "google", "github"). ### Response #### Success Response (200) - **Provider** (`goth.Provider`) - The requested authentication provider. #### Error Response - **error** - An error if the provider with the given name is not found. ### Request Example ```go package main import ( "fmt" "github.com/markbates/goth" ) func getProviderInfo(providerName string) { provider, err := goth.GetProvider(providerName) if err != nil { fmt.Printf("Provider %s not found: %v\n", providerName, err) return } fmt.Printf("Provider name: %s\n", provider.Name()) fmt.Printf("Refresh token available: %v\n", provider.RefreshTokenAvailable()) } // Usage func main() { // After registering providers... getProviderInfo("google") // Works if Google provider was registered getProviderInfo("twitter") // Returns error if not registered } ``` ``` -------------------------------- ### Docker Compose for Nextcloud Source: https://github.com/markbates/goth/blob/master/providers/nextcloud/README.md Use this Docker Compose configuration to set up a Nextcloud instance with Traefik for public URL access. Ensure your NEXTCLOUD_DNS environment variable is set. ```yaml version: '2' networks: traefik-web: external: true services: app: image: nextcloud restart: always networks: - traefik-web labels: - traefik.enable=true - traefik.frontend.rule=Host:${NEXTCLOUD_DNS} - traefik.docker.network=traefik-web environment: SQLITE_DATABASE: "database.sqlite3" NEXTCLOUD_ADMIN_USER: admin NEXTCLOUD_ADMIN_PASSWORD: admin NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DNS} ``` -------------------------------- ### Set Custom Provider Name in Go Source: https://context7.com/markbates/goth/llms.txt Use this when you need multiple instances of the same provider type, such as connecting to different GitHub Enterprise instances or OAuth applications. It involves creating providers with unique names. ```go package main import ( "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/github" ) func main() { // Create multiple GitHub providers with different names githubPublic := github.New( os.Getenv("GITHUB_PUBLIC_KEY"), os.Getenv("GITHUB_PUBLIC_SECRET"), "http://localhost:3000/auth/github-public/callback", ) githubPublic.SetName("github-public") githubEnterprise := github.NewCustomisedURL( os.Getenv("GITHUB_ENTERPRISE_KEY"), os.Getenv("GITHUB_ENTERPRISE_SECRET"), "http://localhost:3000/auth/github-enterprise/callback", "https://github.acme.com/login/oauth/authorize", "https://github.acme.com/login/oauth/access_token", "https://github.acme.com/api/v3/user", "https://github.acme.com/api/v3/user/emails", ) githubEnterprise.SetName("github-enterprise") goth.UseProviders(githubPublic, githubEnterprise) r := mux.NewRouter() // Routes: /auth/github-public and /auth/github-enterprise r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", callbackHandler) http.ListenAndServe(":3000", r) } func callbackHandler(w http.ResponseWriter, r *http.Request) { user, _ := gothic.CompleteUserAuth(w, r) // user.Provider will be "github-public" or "github-enterprise" _ = user } ``` -------------------------------- ### GitHub OAuth2 Authentication Source: https://context7.com/markbates/goth/llms.txt Use this snippet for standard GitHub.com authentication. Ensure GITHUB_KEY and GITHUB_SECRET environment variables are set. The callback URL and requested scopes should be configured as needed. ```go package main import ( "fmt" "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/github" ) func main() { // Standard GitHub.com authentication goth.UseProviders( github.New( os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback", "user:email", "read:user", // Request email and user scopes ), ) // For GitHub Enterprise, use NewCustomisedURL: // github.NewCustomisedURL( // os.Getenv("GITHUB_KEY"), // os.Getenv("GITHUB_SECRET"), // "http://localhost:3000/auth/github/callback", // "https://github.acme.com/login/oauth/authorize", // "https://github.acme.com/login/oauth/access_token", // "https://github.acme.com/api/v3/user", // "https://github.acme.com/api/v3/user/emails", // ) r := mux.NewRouter() r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", func(w http.ResponseWriter, r *http.Request) { user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Printf("GitHub User: %s\n", user.NickName) // GitHub username fmt.Printf("Name: %s\n", user.Name) // Display name fmt.Printf("Email: %s\n", user.Email) // Primary verified email fmt.Printf("Avatar: %s\n", user.AvatarURL) fmt.Printf("Location: %s\n", user.Location) fmt.Printf("Bio: %s\n", user.Description) fmt.Fprintf(w, "Welcome, @%s!", user.NickName) }) http.ListenAndServe(":3000", r) } ``` -------------------------------- ### CompleteUserAuth Source: https://context7.com/markbates/goth/llms.txt Completes the authentication process and retrieves user information from the provider. It validates the OAuth callback, exchanges the authorization code for tokens, and fetches the user's profile, including state validation. ```APIDOC ## POST /auth/{provider}/callback ### Description Completes the OAuth authentication flow after the user has been redirected back from the provider. This handler validates the callback, exchanges the authorization code for tokens, fetches user profile information, and handles state validation. ### Method POST ### Endpoint /auth/{provider}/callback ### Parameters #### Path Parameters - **provider** (string) - Required - The name of the authentication provider. #### Query Parameters - **code** (string) - Required - The authorization code received from the OAuth provider. - **state** (string) - Required - The state parameter used to prevent CSRF attacks. ### Request Example (No explicit request body, relies on query parameters and session state) ### Response #### Success Response (200) - **id** (string) - The unique identifier of the user from the provider. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. - **avatar** (string) - The URL of the user's avatar. - **provider** (string) - The name of the authentication provider. #### Response Example ```json { "id": "123456789", "name": "John Doe", "email": "john.doe@example.com", "avatar": "http://example.com/avatar.jpg", "provider": "google" } ``` ``` -------------------------------- ### Inject Provider into Request Context in Go Source: https://context7.com/markbates/goth/llms.txt Injects the provider name into the request context using gothic.GetContextWithProvider. This is useful when the provider is determined dynamically, such as from a query parameter. ```go package main import ( "net/http" "os" "strings" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" "github.com/markbates/goth/providers/github" ) func main() { goth.UseProviders( google.New(os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/callback"), github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/callback"), ) http.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) { // Determine provider from custom logic (e.g., form submission, header) provider := r.URL.Query().Get("provider") if provider == "" { provider = "google" // default } // Inject provider into request context r = gothic.GetContextWithProvider(r, provider) // Now BeginAuthHandler can find the provider gothic.BeginAuthHandler(w, r) }) http.ListenAndServe(":3000", nil) } ``` -------------------------------- ### Retrieve a Registered Provider by Name Source: https://context7.com/markbates/goth/llms.txt Retrieve a previously registered provider by name. Returns an error if the provider has not been registered. Useful for directly accessing a specific provider's methods or checking its status. ```go package main import ( "fmt" "github.com/markbates/goth" ) func getProviderInfo(providerName string) { provider, err := goth.GetProvider(providerName) if err != nil { fmt.Printf("Provider %s not found: %v\n", providerName, err) return } fmt.Printf("Provider name: %s\n", provider.Name()) fmt.Printf("Refresh token available: %v\n", provider.RefreshTokenAvailable()) } // Usage func main() { // After registering providers... getProviderInfo("google") // Works if Google provider was registered getProviderInfo("twitter") // Returns error if not registered } ``` -------------------------------- ### Clear All Registered Providers for Testing Source: https://context7.com/markbates/goth/llms.txt Remove all registered providers. Primarily used for testing purposes to reset the provider state between test cases. Ensures a clean slate for provider registration. ```go package main import ( "testing" "github.com/markbates/goth" "github.com/markbates/goth/providers/google" ) func TestAuthFlow(t *testing.T) { // Clear any providers from previous tests goth.ClearProviders() // Register only the providers needed for this test goth.UseProviders( google.New("test-key", "test-secret", "http://localhost/callback"), ) // Run test... providers := goth.GetProviders() if len(providers) != 1 { t.Errorf("Expected 1 provider, got %d", len(providers)) } } ``` -------------------------------- ### Refresh Expired Access Token with Google Provider Source: https://context7.com/markbates/goth/llms.txt Demonstrates refreshing an expired access token using a stored refresh token with the Google provider. Ensure the provider supports refresh tokens and handle potential errors during the refresh process. If a new refresh token is issued, it should be stored. ```go package main import ( "fmt" "os" "time" "github.com/markbates/goth" "github.com/markbates/goth/providers/google" ) func main() { googleProvider := google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ) goth.UseProviders(googleProvider) // Assume we have a stored refresh token from a previous auth storedRefreshToken := "stored_refresh_token_from_database" // Check if provider supports refresh tokens if googleProvider.RefreshTokenAvailable() { // Get a new access token newToken, err := googleProvider.RefreshToken(storedRefreshToken) if err != nil { fmt.Printf("Failed to refresh token: %v\n", err) return } fmt.Printf("New access token: %s\n", newToken.AccessToken) fmt.Printf("Token expires at: %s\n", newToken.Expiry) fmt.Printf("Token type: %s\n", newToken.TokenType) // If a new refresh token was issued, store it if newToken.RefreshToken != "" { fmt.Printf("New refresh token: %s\n", newToken.RefreshToken) // Save newToken.RefreshToken to database } } } ``` -------------------------------- ### Log Out User with Logout Source: https://context7.com/markbates/goth/llms.txt Use gothic.Logout to invalidate a user's authentication session by clearing Goth session data from cookies. This logs the user out of the application but does not log them out of the OAuth provider. Requires Goth providers to be configured. ```go package main import ( "net/http" "os" "github.com/gorilla/mux" "github.com/markbates/goth" "github.com/markbates/goth/gothic" "github.com/markbates/goth/providers/google" ) func main() { goth.UseProviders( google.New( os.Getenv("GOOGLE_KEY"), os.Getenv("GOOGLE_SECRET"), "http://localhost:3000/auth/google/callback", ), ) r := mux.NewRouter() r.HandleFunc("/auth/{provider}", gothic.BeginAuthHandler) r.HandleFunc("/auth/{provider}/callback", callbackHandler) r.HandleFunc("/logout/{provider}", func(w http.ResponseWriter, r *http.Request) { err := gothic.Logout(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Redirect to home page after logout http.Redirect(w, r, "/", http.StatusTemporaryRedirect) }) http.ListenAndServe(":3000", r) } func callbackHandler(w http.ResponseWriter, r *http.Request) { user, err := gothic.CompleteUserAuth(w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Handle authenticated user... _ = user } ``` -------------------------------- ### Clearing All Registered Providers Source: https://context7.com/markbates/goth/llms.txt Use `goth.ClearProviders` to remove all currently registered authentication providers. This function is primarily intended for testing scenarios to reset the provider state. ```APIDOC ## goth.ClearProviders ### Description Remove all registered providers. Primarily used for testing purposes to reset the provider state between test cases. ### Method `goth.ClearProviders()` ### Response This function does not return a value. ``` -------------------------------- ### GetAuthURL Source: https://context7.com/markbates/goth/llms.txt Retrieves the authentication URL for a provider without automatically redirecting. This is useful for returning the URL to a frontend application or for more controlled authentication flows. ```APIDOC ## GET /auth/{provider}/url ### Description Generates the authentication URL for a specified provider without initiating the redirect. This allows the client to obtain the URL and handle the redirection itself. ### Method GET ### Endpoint /auth/{provider}/url ### Parameters #### Path Parameters - **provider** (string) - Required - The name of the authentication provider. ### Request Example (No request body for GET requests) ### Response #### Success Response (200) - **auth_url** (string) - The generated URL for initiating the OAuth flow. #### Response Example ```json { "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&client_id=..." } ``` ``` -------------------------------- ### Logout Source: https://context7.com/markbates/goth/llms.txt Invalidates a user's authentication session by clearing the Gothic session data stored in cookies. This logs the user out of the application but does not log them out of the OAuth provider. ```APIDOC ## GET /logout/{provider} ### Description Invalidates the user's current authentication session managed by Goth. This action clears the session data stored in cookies, effectively logging the user out of the application. Note that this does not log the user out from the OAuth provider itself. ### Method GET ### Endpoint /logout/{provider} ### Parameters #### Path Parameters - **provider** (string) - Required - The name of the authentication provider for which to end the session. ### Request Example (No request body for GET requests) ### Response Redirects the user to the root path ("/") upon successful logout. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.