tokens.go raw

   1  package vegadns
   2  
   3  import (
   4  	"context"
   5  	"encoding/json"
   6  	"errors"
   7  	"fmt"
   8  	"io"
   9  	"net/http"
  10  	"net/url"
  11  	"strings"
  12  	"time"
  13  )
  14  
  15  // Token struct to hold token information.
  16  type Token struct {
  17  	Token     string    `json:"access_token"`
  18  	TokenType string    `json:"token_type"`
  19  	ExpiresIn int       `json:"expires_in"`
  20  	ExpiresAt time.Time `json:"-"`
  21  }
  22  
  23  func (t Token) valid() error {
  24  	if t.ExpiresAt.IsZero() || time.Now().UTC().After(t.ExpiresAt) {
  25  		return errors.New("token expired")
  26  	}
  27  
  28  	return nil
  29  }
  30  
  31  func (t Token) formatBearer() string {
  32  	return "Bearer " + t.Token
  33  }
  34  
  35  func (c *Client) getAuthToken(ctx context.Context) (Token, error) {
  36  	data := url.Values{}
  37  	data.Set("grant_type", "client_credentials")
  38  
  39  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL.JoinPath("token").String(), strings.NewReader(data.Encode()))
  40  	if err != nil {
  41  		return Token{}, fmt.Errorf("get auth token: %w", err)
  42  	}
  43  
  44  	req.SetBasicAuth(c.apiKey, c.apiSecret)
  45  
  46  	req.Header.Set("Content-Type", contentType)
  47  
  48  	issueTime := time.Now().UTC()
  49  
  50  	resp, err := c.httpClient.Do(req)
  51  	if err != nil {
  52  		return Token{}, fmt.Errorf("get auth token: %w", err)
  53  	}
  54  
  55  	defer resp.Body.Close()
  56  
  57  	if resp.StatusCode != http.StatusOK {
  58  		body, _ := io.ReadAll(resp.Body)
  59  
  60  		return Token{}, fmt.Errorf("get auth token: bad answer from VegaDNS (code: %d, message: %s)", resp.StatusCode, string(body))
  61  	}
  62  
  63  	body, err := io.ReadAll(resp.Body)
  64  	if err != nil {
  65  		return Token{}, fmt.Errorf("get auth token: response: %w", err)
  66  	}
  67  
  68  	tok := Token{}
  69  
  70  	if err := json.Unmarshal(body, &tok); err != nil {
  71  		return Token{}, fmt.Errorf("get auth token: unmarshalling body: %w", err)
  72  	}
  73  
  74  	if tok.TokenType != "bearer" {
  75  		return Token{}, fmt.Errorf("get auth token: don't support anything except bearer tokens (token type: %s)", c.token.TokenType)
  76  	}
  77  
  78  	tok.ExpiresAt = issueTime.Add(time.Duration(tok.ExpiresIn) * time.Second)
  79  
  80  	return tok, nil
  81  }
  82