Skip to content

Instantly share code, notes, and snippets.

@goodylili
Created December 30, 2023 08:42
Show Gist options
  • Save goodylili/f93485b16147dfac2c8c1e7ce5ce73d5 to your computer and use it in GitHub Desktop.
Save goodylili/f93485b16147dfac2c8c1e7ce5ce73d5 to your computer and use it in GitHub Desktop.
GitHub OAuth Golang
package main
import (
"context"
"encoding/json"
"fmt"
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
"io"
"net/http"
)
var (
// Configuration for GitHub OAuth
GitHubOAuthConfig = &oauth2.Config{
RedirectURL: "http://localhost:8080/auth/callback",
ClientID: "",
ClientSecret: "",
Scopes: []string{"user:email"},
Endpoint: github.Endpoint,
}
oauthStateString = "random" // Replace this with a random state string for production
)
// GitHubUser represents the GitHub user information
type GitHubUser struct {
ID int `json:"id"`
Username string `json:"login"` // GitHub username
AvatarURL string `json:"avatar_url"`
Email string `json:"email"`
}
// HandleGitHubLogin redirects the user to the GitHub login page
func HandleGitHubLogin(w http.ResponseWriter, r *http.Request) {
url := GitHubOAuthConfig.AuthCodeURL(oauthStateString)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
// HandleGitHubCallback processes the OAuth callback from GitHub
func HandleGitHubCallback(w http.ResponseWriter, r *http.Request) {
user, err := GetUserInfo(r.URL.Query().Get("state"), r.URL.Query().Get("code"))
if err != nil {
fmt.Println(err.Error())
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
jsonData, err := json.Marshal(user)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)
}
// GetUserInfo retrieves the user information from GitHub
func GetUserInfo(state string, code string) (GitHubUser, error) {
var user GitHubUser
if state != oauthStateString {
return user, fmt.Errorf("invalid oauth state")
}
token, err := GitHubOAuthConfig.Exchange(context.TODO(), code)
if err != nil {
return user, fmt.Errorf("code exchange failed: %s", err.Error())
}
client := &http.Client{}
req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
if err != nil {
return user, fmt.Errorf("failed creating request: %s", err.Error())
}
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
resp, err := client.Do(req)
if err != nil {
return user, fmt.Errorf("failed getting user info: %s", err.Error())
}
defer resp.Body.Close()
contents, err := io.ReadAll(resp.Body)
if err != nil {
return user, fmt.Errorf("failed reading response body: %s", err.Error())
}
err = json.Unmarshal(contents, &user)
if err != nil {
return user, fmt.Errorf("failed unmarshalling user info: %s", err.Error())
}
return user, nil
}
func main() {
http.HandleFunc("/login", HandleGitHubLogin)
http.HandleFunc("/auth/callback", HandleGitHubCallback)
fmt.Println("Starting server on :8080...")
http.ListenAndServe(":8080", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment