ExchangeDeviceCode exchanges a device code for an access token. The boolean returned indicates whether the device code is still pending and the caller should try again.
(ctx context.Context, deviceCode string)
| 746 | // The boolean returned indicates whether the device code is still pending |
| 747 | // and the caller should try again. |
| 748 | func (c *DeviceAuth) ExchangeDeviceCode(ctx context.Context, deviceCode string) (*oauth2.Token, error) { |
| 749 | if c.TokenURL == "" { |
| 750 | return nil, xerrors.New("oauth2: token URL not set") |
| 751 | } |
| 752 | tokenURL, err := c.formatDeviceTokenURL(deviceCode) |
| 753 | if err != nil { |
| 754 | return nil, err |
| 755 | } |
| 756 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenURL, nil) |
| 757 | if err != nil { |
| 758 | return nil, err |
| 759 | } |
| 760 | req.Header.Set("Accept", "application/json") |
| 761 | resp, err := http.DefaultClient.Do(req) |
| 762 | if err != nil { |
| 763 | return nil, err |
| 764 | } |
| 765 | defer resp.Body.Close() |
| 766 | if resp.StatusCode != http.StatusOK { |
| 767 | return nil, codersdk.ReadBodyAsError(resp) |
| 768 | } |
| 769 | var body ExchangeDeviceCodeResponse |
| 770 | err = json.NewDecoder(resp.Body).Decode(&body) |
| 771 | if err != nil { |
| 772 | return nil, err |
| 773 | } |
| 774 | if body.Error != "" { |
| 775 | return nil, xerrors.New(body.Error) |
| 776 | } |
| 777 | // If expiresIn is 0, then the token never expires. |
| 778 | expires := dbtime.Now().Add(time.Duration(body.ExpiresIn) * time.Second) |
| 779 | if body.ExpiresIn == 0 { |
| 780 | expires = time.Time{} |
| 781 | } |
| 782 | return &oauth2.Token{ |
| 783 | AccessToken: body.AccessToken, |
| 784 | RefreshToken: body.RefreshToken, |
| 785 | Expiry: expires, |
| 786 | }, nil |
| 787 | } |
| 788 | |
| 789 | func (c *DeviceAuth) formatDeviceTokenURL(deviceCode string) (string, error) { |
| 790 | tok, err := url.Parse(c.TokenURL) |
no test coverage detected