2024-09-13 20:06:00 +00:00
|
|
|
package cognito_auth
|
2024-09-13 19:39:02 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/hmac"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/config"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
CognitoClient *cognitoidentityprovider.Client
|
|
|
|
poolId string
|
|
|
|
clientId string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAuthClient(poolID string, clientId string) (AuthClient, error) {
|
|
|
|
sdkConfig, err := config.LoadDefaultConfig(context.TODO())
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cognitoClient := cognitoidentityprovider.NewFromConfig(sdkConfig)
|
|
|
|
|
|
|
|
return &Client{CognitoClient: cognitoClient, poolId: poolID, clientId: clientId}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthClient interface {
|
|
|
|
SignUp(req SignUpRequest) error
|
|
|
|
ConfirmSignUp(req ConfirmSignUpRequest) error
|
|
|
|
SignIn(ctx context.Context, username, password string) (*AuthenticationResult, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type SignUpRequest struct {
|
|
|
|
Username string `json:"username" binding:"required"`
|
|
|
|
Password string `json:"password" binding:"required"`
|
|
|
|
Email string `json:"email" binding:"required,email"`
|
|
|
|
Context context.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) SignUp(req SignUpRequest) error {
|
|
|
|
secretHash := getSecretHash(req.Username, *&c.clientId)
|
|
|
|
params := &cognitoidentityprovider.SignUpInput{
|
|
|
|
ClientId: aws.String(c.clientId),
|
|
|
|
Username: aws.String(req.Username),
|
|
|
|
Password: aws.String(req.Password),
|
|
|
|
UserAttributes: []types.AttributeType{
|
|
|
|
{Name: aws.String("email"), Value: aws.String(req.Email)},
|
|
|
|
},
|
|
|
|
SecretHash: &secretHash,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := c.CognitoClient.SignUp(context.Background(), params)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
type ConfirmSignUpRequest struct {
|
|
|
|
Context context.Context
|
|
|
|
Username string
|
|
|
|
ConfirmationCode string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) ConfirmSignUp(req ConfirmSignUpRequest) error {
|
|
|
|
input := &cognitoidentityprovider.ConfirmSignUpInput{
|
|
|
|
ClientId: aws.String(c.clientId),
|
|
|
|
Username: aws.String(req.Username),
|
|
|
|
ConfirmationCode: aws.String(req.ConfirmationCode),
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := c.CognitoClient.ConfirmSignUp(req.Context, input)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type SignInRequest struct {
|
|
|
|
Username string `json:"username"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignIn authenticates a user and returns tokens
|
|
|
|
func (c *Client) SignIn(ctx context.Context, username, password string) (*AuthenticationResult, error) {
|
|
|
|
authParams := map[string]string{
|
|
|
|
"USERNAME": username,
|
|
|
|
"PASSWORD": password,
|
|
|
|
}
|
|
|
|
|
|
|
|
input := &cognitoidentityprovider.InitiateAuthInput{
|
|
|
|
AuthFlow: types.AuthFlowTypeUserPasswordAuth,
|
|
|
|
ClientId: aws.String(c.clientId),
|
|
|
|
AuthParameters: authParams,
|
|
|
|
}
|
|
|
|
|
|
|
|
output, err := c.CognitoClient.InitiateAuth(ctx, input)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if output.AuthenticationResult == nil {
|
|
|
|
return nil, errors.New("authentication result is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &AuthenticationResult{
|
|
|
|
IDToken: aws.ToString(output.AuthenticationResult.IdToken),
|
|
|
|
AccessToken: aws.ToString(output.AuthenticationResult.AccessToken),
|
|
|
|
RefreshToken: aws.ToString(output.AuthenticationResult.RefreshToken),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AuthenticationResult holds the tokens returned after successful authentication
|
|
|
|
type AuthenticationResult struct {
|
|
|
|
IDToken string
|
|
|
|
AccessToken string
|
|
|
|
RefreshToken string
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSecretHash(username string, clientID string) string {
|
|
|
|
secret := os.Getenv("COGNITO_SECRET")
|
|
|
|
if secret == "" {
|
|
|
|
secret = "1bb1r4fegke1hcn6rjo8d38io5np0qcce7juhjb8hu4kvu6qfr3s"
|
|
|
|
}
|
|
|
|
mac := hmac.New(sha256.New, []byte(secret))
|
|
|
|
mac.Write([]byte(fmt.Sprintf("%s%s", username, clientID)))
|
|
|
|
|
|
|
|
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
|
|
}
|