/
exchange.go
94 lines (74 loc) · 2.71 KB
/
exchange.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package libgh
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/Noah-Huppert/gh-gantt/server/config"
)
// ExchangeGitHubCodeURL is the GitHub API URL used to exchange a GitHub code for a token
const exchangeGitHubCodeURL string = "https://github.com/login/oauth/access_token"
// ExchangeGitHubCodeRequest holds the parameters required to make a GitHub API request to exchange a temporary GitHub
// code for a longer lasting GitHub token
type ExchangeGitHubCodeRequest struct {
// ClientID is the GitHub app's Client ID
ClientID string `json:"client_id"`
// ClientSecret is the GitHub app's client secret
ClientSecret string `json:"client_secret"`
// Code is the temporary GitHub authentication code
Code string `json:"code"`
// State is a value used to prevent cross site request forgery
State string `json:"state"`
}
// exchangeGitHubCodeResp is the format of the exchange GitHub API response
type exchangeGitHubCodeResp struct {
// AccessToken is the long lasting GitHub authentication token
AccessToken string `json:"access_token"`
// Error is not empty if the GitHub API request failed
Error string `json:"error"`
}
// NewExchangeGitHubCodeRequest creates a new ExchangeGitHubCodeRequest. Most of the fields can be filled by passing an
// config.Config object
func NewExchangeGitHubCodeRequest(cfg config.Config, code, state string) ExchangeGitHubCodeRequest {
return ExchangeGitHubCodeRequest{
ClientID: cfg.GitHubClientID,
ClientSecret: cfg.GitHubClientSecret,
Code: code,
State: state,
}
}
// Exchange exchanges a temporary GitHub code for a longer lasting GitHub token
func (r ExchangeGitHubCodeRequest) Do() (string, error) {
// Encode request body
var body []byte
reqBodyBuffer := bytes.NewBuffer(body)
encoder := json.NewEncoder(reqBodyBuffer)
err := encoder.Encode(r)
if err != nil {
return "", fmt.Errorf("error JSON encoding request body: %s", err.Error())
}
// Setup request
req, err := http.NewRequest(http.MethodPost, exchangeGitHubCodeURL, reqBodyBuffer)
if err != nil {
return "", fmt.Errorf("error setting up request: %s", err.Error())
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
// Execute request
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", fmt.Errorf("error GitHub API request: %s", err.Error())
}
// Decode request
var ghResp exchangeGitHubCodeResp
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&ghResp)
if err != nil {
return "", fmt.Errorf("error decoding GitHub API response body: %s", err.Error())
}
if len(ghResp.Error) > 0 {
return "", fmt.Errorf("error returned by GitHub API: %s", ghResp.Error)
}
// Success
return ghResp.AccessToken, nil
}