all repos

onasty @ 060f2e6

a one-time notes service

onasty/internal/oauth/github.go (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
feat: add oauth2 login for google and github (#109)..., 1 year ago
1
package oauth
2
3
import (
4
	"bytes"
5
	"context"
6
	"encoding/json"
7
	"io"
8
	"net/http"
9
	"strconv"
10
11
	"golang.org/x/oauth2"
12
	"golang.org/x/oauth2/github"
13
)
14
15
var _ Provider = (*GitHubProvider)(nil)
16
17
const githubUserInfoEndpoint = "https://api.github.com/user"
18
19
type GitHubProvider struct {
20
	config oauth2.Config
21
}
22
23
func NewGithubProvider(clientID, secret, redirectURL string) GitHubProvider {
24
	return GitHubProvider{
25
		config: oauth2.Config{
26
			ClientID:     clientID,
27
			ClientSecret: secret,
28
			RedirectURL:  redirectURL,
29
			Endpoint:     github.Endpoint,
30
			Scopes: []string{
31
				"user:email",
32
			},
33
		},
34
	}
35
}
36
37
func (g GitHubProvider) GetAuthURL(state string) string {
38
	return g.config.AuthCodeURL(state)
39
}
40
41
func (g GitHubProvider) ExchangeCode(ctx context.Context, code string) (UserInfo, error) {
42
	tok, err := g.config.Exchange(ctx, code)
43
	if err != nil {
44
		return UserInfo{}, err
45
	}
46
47
	client := g.config.Client(ctx, tok)
48
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, githubUserInfoEndpoint, nil)
49
	if err != nil {
50
		return UserInfo{}, err
51
	}
52
53
	resp, err := client.Do(req)
54
	if err != nil {
55
		return UserInfo{}, err
56
	}
57
58
	defer resp.Body.Close()
59
60
	b, err := io.ReadAll(resp.Body)
61
	if err != nil {
62
		return UserInfo{}, err
63
	}
64
65
	var data struct {
66
		ID    int    `json:"id"`
67
		Email string `json:"email"`
68
	}
69
70
	if err := json.NewDecoder(bytes.NewReader(b)).Decode(&data); err != nil {
71
		return UserInfo{}, err
72
	}
73
74
	return UserInfo{
75
		Provider:      "github",
76
		ProviderID:    strconv.Itoa(data.ID),
77
		Email:         data.Email,
78
		EmailVerified: true,
79
	}, nil
80
}