forked from danielgtaylor/restish
/
request.go
69 lines (57 loc) · 1.7 KB
/
request.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
package oauth
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/barbich/restish/cli"
"golang.org/x/oauth2"
)
// tokenResponse is used to parse responses from token providers and make sure
// the expiration time is set properly regardless of whether `expires_in` or
// `expiry` is returned.
type tokenResponse struct {
TokenType string `json:"token_type"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token,omitempty"`
ExpiresIn time.Duration `json:"expires_in"`
Expiry time.Time `json:"expiry,omitempty"`
}
// requestToken from the given URL with the given payload. This can be used
// for many different grant types and will return a parsed token.
func requestToken(tokenURL, payload string) (*oauth2.Token, error) {
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(payload))
if err != nil {
return nil, err
}
req.Header.Add("content-type", "application/x-www-form-urlencoded")
cli.LogDebugRequest(req)
start := time.Now()
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
cli.LogDebugResponse(start, res)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if res.StatusCode > 200 {
return nil, fmt.Errorf("bad response from token endpoint:\n%s", body)
}
decoded := tokenResponse{}
if err := json.Unmarshal(body, &decoded); err != nil {
return nil, err
}
expiry := decoded.Expiry
if expiry.IsZero() {
expiry = time.Now().Add(decoded.ExpiresIn * time.Second)
}
token := &oauth2.Token{
AccessToken: decoded.AccessToken,
TokenType: decoded.TokenType,
RefreshToken: decoded.RefreshToken,
Expiry: expiry,
}
return token, nil
}