package main import ( "bytes" "encoding/json" "fmt" "io" "nats-w-auth/internal/users" "net/http" "os" "strconv" ) // https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-a-user type GitHubUser struct { Name string Avatar_url string ID int } func githubSuccessHandler(w http.ResponseWriter, r *http.Request) { provider := "github" code := r.URL.Query().Get("code") fmt.Println("callback from github", code) token, err := tokenForCode(code) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Println("access token", token) ghUser, err := getGithubUser(token) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Println("user", ghUser) sessionManager.Put(r.Context(), "pie", ghUser.Name) user, err := userManager.GetOAuthUser(r.Context(), provider, strconv.Itoa(ghUser.ID)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if user == nil { // TODO: Create core user // TODO: Create user/oauth connection fmt.Println("we should create user", user) user, err = userManager.CreateUser(r.Context(), users.UserModelInfo{ Name: ghUser.Name, AvatarURL: ghUser.Avatar_url, }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } err = userManager.LinkUserProvider(r.Context(), user, provider, strconv.Itoa(ghUser.ID)) sessionManager.Put(r.Context(), "user_id", user.ID) sessionManager.Put(r.Context(), "name", user.Name) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // TODO: Find or create user according to GitHub user_id // TODO: Set (our) user_id, user on session // DONE http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } func tokenForCode(code string) (string, error) { // TODO: Validate the code url := "https://github.com/login/oauth/access_token" payload := map[string]string{ "client_id": os.Getenv("GH_CLIENT_ID"), "client_secret": os.Getenv("GH_CLIENT_SECRET"), "code": code, } body, _ := json.Marshal(payload) req, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) if err != nil { return "", err } req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() respBody, _ := io.ReadAll(resp.Body) var tokenResp map[string]any if err := json.Unmarshal(respBody, &tokenResp); err != nil { return "", err } token, ok := tokenResp["access_token"].(string) if !ok { return "", fmt.Errorf("no access toke in response: %v", tokenResp) } return token, nil } func getGithubUser(token string) (*GitHubUser, error) { url := "https://api.github.com/user" req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("GitHub API responded with %d", resp.StatusCode) } body, _ := io.ReadAll(resp.Body) //fmt.Println("user data", body) var user GitHubUser if err := json.Unmarshal(body, &user); err != nil { return nil, err } fmt.Println("github user", user) return &user, nil }