Skip to content

Instantly share code, notes, and snippets.

@lucasmarques73
Created August 29, 2019 18:41
Show Gist options
  • Save lucasmarques73/8e99d4be01fd767583d47bf2c30fd6f4 to your computer and use it in GitHub Desktop.
Save lucasmarques73/8e99d4be01fd767583d47bf2c30fd6f4 to your computer and use it in GitHub Desktop.
Auth Social
// Rota para autenticacao customizada
r.POST("/custom-signin", ctrl.handleCustomSignIn)

Eu recebo no input

  • JWT Token da rede social(input.Token)
  • Qual rede social (input.Provider)
  • FederationID (input.GoogleID || input.FacebookID)
// INICIO Controller Autenticacao
func (c *authController) handleCustomSignIn(ctx echo.Context) error {

	context := context.New()
	txn := ctx.Get(domain.NRTransactionKey)
	context.Set(domain.NRTransactionKey, txn)

	input := auth.UserDataCognito{}
	err := ctx.Bind(&input)
	if err != nil {
		return errors.NewValidationError("", "Formato de entrada inválido")
	}

	cognitoService := auth.NewCognitoService()

	// Validate token
	err = auth.ValidateFederationToken(&input)
	if err != nil {
		return routeutils.HandleAPIError(ctx, errors.Wrap(err))
	}

	// Map federationIDs
	federationID := map[string]string{
		"google":   input.GoogleID,
		"facebook": input.FacebookID,
	}

	// Get user on Cognito with userID
	user, err := c.svc.User.GetByFederationIDorEmail(context, federationID[input.Provider], input.Email)
	if err != nil {
		return routeutils.HandleAPIError(ctx, errors.Wrap(err))
	}

	// If user not found - Create a New
	if user.ID == 0 {
		userDataCognito, err := cognitoService.SignUp(input)
		if err != nil {
			return errors.NewHTTPError(403, err.Error())
		}
		input.ID = userDataCognito.ID

		user := mapping.AuthCognitoToUserEntity(input)

		user, err = c.svc.User.Insert(context, user)
		if err != nil {
			return routeutils.HandleAPIError(ctx, errors.Wrap(err))
		}
	}

	// If user found - generate token
	result, err := cognitoService.CustomSignIn(input)
	if err != nil {
		return errors.NewHTTPError(403, err.Error())
	}

	user, err = c.svc.User.GetByEmail(context, input.Email)
	if err != nil {
		return routeutils.HandleAPIError(ctx, errors.Wrap(err))
	}

	response := map[string]interface{}{
		"token":         result.IdToken,
		"refresh_token": result.RefreshToken,
		"expire_in":     result.ExpiresIn,
		"user":          mapping.UserEntityToResponse(user),
	}

	return routeutils.ResponseAPIOK(ctx, response)
}
// FIM Controller

Dentro do metodo cognitoService.CustomSignIn(input)
Eu crio um novo JWT

// Auth
func ValidateFederationToken(input *UserDataCognito) error {
    switch input.Provider {
	case "google":
		return validateGoogleToken(input)
	case "facebook":
		return validateFacebookToken(input)
	}
	return nil
}

func validateFacebookToken(input *UserDataCognito) error {

	url := "https://graph.facebook.com/v3.2/me?fields=id,name,email"

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return errors.Wrap(err)
	}

	req.Header.Add("Host", "graph.facebook.com")
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", input.Token))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.Wrap(err)
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return errors.Wrap(err)
	}

	if res.StatusCode != http.StatusOK {
		return errors.NewForbiddenError("Invalid Token")
	}

	var response FacebookData
	err = json.Unmarshal(body, &response)
	if err != nil {
		return errors.Wrap(err)
	}

	input.Name = response.Name
	input.Email = response.Email
	input.FacebookID = response.ID
	input.Password = strconv.FormatInt(time.Now().UnixNano(), 10)[0:9] // Random Password

	return nil
}

func validateGoogleToken(input *UserDataCognito) error {

	url := fmt.Sprintf("https://oauth2.googleapis.com/tokeninfo?id_token=%s", input.Token)

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return errors.Wrap(err)
	}

	req.Header.Add("Host", "oauth2.googleapis.com")
	req.Header.Add("accept-encoding", "gzip, deflate")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.Wrap(err)
	}

	var reader io.ReadCloser
	switch res.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err = gzip.NewReader(res.Body)
		defer reader.Close()
	default:
		reader = res.Body
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(reader)

	var response GoogleData
	err = json.Unmarshal(body, &response)
	if err != nil {
		return errors.Wrap(err)
	}

	input.Name = response.Name
	input.Email = response.Email
	input.GoogleID = response.Sub
	input.Password = strconv.FormatInt(time.Now().UnixNano(), 10)[0:9] // Random Password

	return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment