Last active
August 18, 2024 15:10
-
-
Save KaiserWerk/322b5ee66eed7826da459204d70c3397 to your computer and use it in GitHub Desktop.
Quick and dirty example for a discord social login with Golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io" | |
"net/http" | |
"path" | |
"text/template" | |
"net/url" | |
"encoding/json" | |
"strings" | |
) | |
type accessTokenResponse struct { | |
AccessToken string `json:"access_token"` | |
TokenType string `json:"token_type"` | |
ExpiresIn uint `json:"expires_in"` | |
RefreshToken string `json:"refresh_token"` | |
Scope string `json:"scope"` | |
} | |
type UserInfo struct { | |
ID string `json:"id"` | |
Username string `json:"username"` | |
GlobalName string `json:"global_name"` | |
MfaEnabled bool `json:"mfa_enabled"` | |
Locale string `json:"locale"` | |
Email string `json:"email"` | |
Verified bool `json:"verified"` | |
} | |
var ( | |
token = "" | |
redirectURL = "http://localhost:8080/callback" | |
authURL = "<your generated authorization url here>" | |
tokenURL = "https://discord.com/api/oauth2/token" | |
clientID = "<your client id here>" | |
clientSecret = "<your client secret here>" | |
apiURL = "https://discord.com/api" | |
client = http.Client{} | |
userInfo UserInfo | |
rawUserInfo string | |
) | |
func main() { | |
http.HandleFunc("/", handleAuthInit) | |
http.HandleFunc("/callback", handleCallback) | |
fmt.Println("starting up server on :8080...") | |
http.ListenAndServe(":8080", nil) | |
} | |
func handleAuthInit(w http.ResponseWriter, r *http.Request) { | |
if token != "" { | |
getUserInfo() | |
} | |
data := struct { | |
Token string | |
AuthURL string | |
UserInfo string | |
}{ | |
Token: token, | |
AuthURL: authURL, | |
UserInfo: rawUserInfo, | |
} | |
executeTemplate(w, "templates/authorize.html", data) | |
} | |
func handleCallback(w http.ResponseWriter, r *http.Request) { | |
code := r.URL.Query().Get("code") | |
values := url.Values{} | |
values.Add("grant_type", "authorization_code") | |
values.Add("code", code) | |
values.Add("redirect_uri", redirectURL) | |
values.Add("client_id", clientID) | |
values.Add("client_secret", clientSecret) | |
req, _ := http.NewRequest(http.MethodPost, tokenURL, strings.NewReader(values.Encode())) | |
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | |
resp, err := client.Do(req) | |
if err != nil { | |
panic(err) | |
} | |
body, err := io.ReadAll(resp.Body) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("%s\n", body) | |
var tokenResponse accessTokenResponse | |
err = json.Unmarshal(body, &tokenResponse) | |
if err != nil { | |
panic(err) | |
} | |
token = tokenResponse.AccessToken | |
fmt.Printf("%+v\n", tokenResponse) | |
http.Redirect(w, r, "/", http.StatusSeeOther) | |
} | |
func executeTemplate(w io.Writer, tmplFile string, data any) { | |
tmpl, err := template.New(path.Base(tmplFile)).ParseFiles(tmplFile) | |
if err != nil { | |
panic(err) | |
} | |
err = tmpl.Execute(w, data) | |
if err != nil { | |
panic(err) | |
} | |
} | |
func getUserInfo() { | |
req, _ := http.NewRequest(http.MethodGet, apiURL + "/users/@me", nil) | |
req.Header.Add("Authorization", "Bearer " + token); | |
resp, err := client.Do(req) | |
if err != nil { | |
panic(err) | |
} | |
body, err := io.ReadAll(resp.Body) | |
resp.Body.Close() | |
if err != nil { | |
panic(err) | |
} | |
var ui UserInfo | |
err = json.Unmarshal(body, &ui) | |
if err != nil { | |
panic(err) | |
} | |
userInfo = ui | |
rawUserInfo = string(body) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment