Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
140
pkg/auth/user_consent_token.go
Normal file
140
pkg/auth/user_consent_token.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"fiskerinc.com/modules/httpclient"
|
||||
"fiskerinc.com/modules/jwt"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/utils/envtool"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var cognitoUserConsentClientID = envtool.GetEnv("COGNITO_USER_CONSENT_CLIENT_ID", "REPLACE_ME")
|
||||
var cognitoUserConsentClientSecret = envtool.GetEnv("COGNITO_USER_CONSENT_CLIENT_SECRET", "REPLACE_ME")
|
||||
var cognitoUserConsentAuthURL = envtool.GetEnv("COGNITO_USER_CONSENT_AUTH_URL", "REPLACE_ME")
|
||||
|
||||
var CognitoUserConsentJWT CognitoJWT
|
||||
|
||||
type CognitoJWT struct {
|
||||
token string
|
||||
expiration *time.Time
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *CognitoJWT) GetUserConsentToken() (string, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// check for an unexpired token. if it is there, return it
|
||||
if c.token != "" && time.Now().Before(*c.expiration) {
|
||||
return c.token, nil
|
||||
}
|
||||
|
||||
// make a request to Cognito to get the token
|
||||
authResponse, err := RequestUserConsentToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// cache the token and expire time
|
||||
c.token = authResponse.AccessToken.JWTToken
|
||||
c.expiration = &authResponse.ExpireTime
|
||||
|
||||
return c.token, nil
|
||||
}
|
||||
|
||||
func RequestUserConsentToken() (AuthResponse, error) {
|
||||
var resp AuthTokens
|
||||
var tokens AuthResponse
|
||||
|
||||
tokenReq, err := getUserConsentTokenRequest()
|
||||
if err != nil {
|
||||
return tokens, err
|
||||
}
|
||||
|
||||
tokenRes, err := httpclient.Do(tokenReq)
|
||||
if err != nil {
|
||||
return tokens, err
|
||||
}
|
||||
defer tokenRes.Body.Close()
|
||||
|
||||
err = json.NewDecoder(tokenRes.Body).Decode(&resp)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
}
|
||||
|
||||
if len(resp.Error) > 0 {
|
||||
return tokens, errors.New(resp.Error)
|
||||
}
|
||||
|
||||
return getAuthResponse(&resp), nil
|
||||
}
|
||||
|
||||
// getUserConsentTokenRequest returns http request to exchange code for a user consent token
|
||||
func getUserConsentTokenRequest() (*http.Request, error) {
|
||||
basicAuth := base64.StdEncoding.EncodeToString([]byte(strings.Join([]string{cognitoUserConsentClientID, ":", cognitoUserConsentClientSecret}, "")))
|
||||
|
||||
body := url.Values{
|
||||
"client_id": {cognitoUserConsentClientID},
|
||||
"grant_type": {"client_credentials"},
|
||||
}
|
||||
|
||||
r, err := http.NewRequest(http.MethodPost, getUserConsentTokenURL(), strings.NewReader(body.Encode()))
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
r.Header.Add("Authorization", fmt.Sprintf("Basic %s", basicAuth))
|
||||
r.Header.Add("Content-type", "application/x-www-form-urlencoded")
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// GetAuthResponse converts AuthTokens response from Cognito to include decoded payload
|
||||
func getAuthResponse(data *AuthTokens) AuthResponse {
|
||||
var result AuthResponse
|
||||
|
||||
result.AccessToken.JWTToken = data.AcessToken
|
||||
result.IDToken.JWTToken = data.IDToken
|
||||
result.RefreshToken.Token = data.RefreshToken
|
||||
|
||||
// calculate the expire time of the token, leaving off one minute of wiggle room
|
||||
result.ExpireTime = time.Now().Add(time.Duration(data.ExpiresIn)*time.Second - time.Minute)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getUserConsentTokenURL() string {
|
||||
return cognitoUserConsentAuthURL + "/oauth2/token"
|
||||
}
|
||||
|
||||
// AuthTokens json response for auth tokens
|
||||
type AuthTokens struct {
|
||||
AcessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
IDToken string `json:"id_token,omitempty"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// JWTResponse json response
|
||||
type JWTResponse struct {
|
||||
JWTToken string `json:"jwtToken"`
|
||||
}
|
||||
|
||||
// AuthResponse json response
|
||||
type AuthResponse struct {
|
||||
AccessToken JWTResponse `json:"accessToken,omitempty"`
|
||||
IDToken JWTResponse `json:"idToken,omitempty"`
|
||||
RefreshToken jwt.AuthToken `json:"refreshToken,omitempty"`
|
||||
ExpireTime time.Time `json:"expire_time"`
|
||||
}
|
||||
Reference in New Issue
Block a user