UPDATE: Add rederict
All checks were successful
Build and Release / release (push) Successful in 1m7s
All checks were successful
Build and Release / release (push) Successful in 1m7s
This commit is contained in:
@@ -2,11 +2,13 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"history-api/internal/dtos/request"
|
"history-api/internal/dtos/request"
|
||||||
"history-api/internal/dtos/response"
|
"history-api/internal/dtos/response"
|
||||||
|
"history-api/internal/models"
|
||||||
"history-api/internal/services"
|
"history-api/internal/services"
|
||||||
"history-api/pkg/validator"
|
"history-api/pkg/validator"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
@@ -296,20 +298,32 @@ func (h *AuthController) ForgotPassword(c fiber.Ctx) error {
|
|||||||
func (h *AuthController) GoogleLogin(c fiber.Ctx) error {
|
func (h *AuthController) GoogleLogin(c fiber.Ctx) error {
|
||||||
_, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
_, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
state := uuid.New().String()
|
state := uuid.New().String()
|
||||||
|
|
||||||
secure := c.Protocol() == "https"
|
redirect := c.Query("redirect")
|
||||||
|
if redirect == "" {
|
||||||
|
redirect = "http://localhost:3000"
|
||||||
|
}
|
||||||
|
|
||||||
|
data := models.OAuthState{
|
||||||
|
State: state,
|
||||||
|
RedirectURL: redirect,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, _ := json.Marshal(data)
|
||||||
|
encoded := base64.URLEncoding.EncodeToString(b)
|
||||||
|
|
||||||
c.Cookie(&fiber.Cookie{
|
c.Cookie(&fiber.Cookie{
|
||||||
Name: "oauth_state",
|
Name: "oauth_state",
|
||||||
Value: state,
|
Value: state,
|
||||||
Expires: time.Now().Add(15 * time.Minute),
|
Expires: time.Now().Add(15 * time.Minute),
|
||||||
HTTPOnly: true,
|
HTTPOnly: true,
|
||||||
Secure: secure,
|
Secure: c.Protocol() == "https",
|
||||||
SameSite: "None",
|
SameSite: "None",
|
||||||
})
|
})
|
||||||
|
|
||||||
url := h.oauth.AuthCodeURL(state)
|
url := h.oauth.AuthCodeURL(encoded)
|
||||||
return c.Redirect().To(url)
|
return c.Redirect().To(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,18 +340,31 @@ func (h *AuthController) GoogleLogin(c fiber.Ctx) error {
|
|||||||
func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
|
func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
stateFromGoogle := c.Query("state")
|
|
||||||
stateFromCookie := c.Cookies("oauth_state")
|
|
||||||
|
|
||||||
if stateFromGoogle == "" || stateFromGoogle != stateFromCookie {
|
encoded := c.Query("state")
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid state"})
|
|
||||||
|
b, err := base64.URLEncoding.DecodeString(encoded)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(400).JSON(fiber.Map{"error": "Invalid state"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var data models.OAuthState
|
||||||
|
if err := json.Unmarshal(b, &data); err != nil {
|
||||||
|
return c.Status(400).JSON(fiber.Map{"error": "Invalid state"})
|
||||||
|
}
|
||||||
|
|
||||||
|
stateFromCookie := c.Cookies("oauth_state")
|
||||||
|
if data.State != stateFromCookie {
|
||||||
|
return c.Status(401).JSON(fiber.Map{"error": "Invalid state"})
|
||||||
|
}
|
||||||
|
|
||||||
c.ClearCookie("oauth_state")
|
c.ClearCookie("oauth_state")
|
||||||
|
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
token, err := h.oauth.Exchange(context.Background(), code)
|
|
||||||
|
token, err := h.oauth.Exchange(ctx, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Token exchange failed"})
|
return c.Status(500).JSON(fiber.Map{"error": "Token exchange failed"})
|
||||||
}
|
}
|
||||||
|
|
||||||
idToken, ok := token.Extra("id_token").(string)
|
idToken, ok := token.Extra("id_token").(string)
|
||||||
@@ -345,14 +372,9 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
|
|||||||
return c.Status(500).JSON(fiber.Map{"error": "No id_token"})
|
return c.Status(500).JSON(fiber.Map{"error": "No id_token"})
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(idToken, ".")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return c.Status(500).JSON(fiber.Map{"error": "Invalid id_token"})
|
|
||||||
}
|
|
||||||
|
|
||||||
payload, err := idtoken.Validate(ctx, idToken, h.oauth.ClientID)
|
payload, err := idtoken.Validate(ctx, idToken, h.oauth.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Token verification failed"})
|
return c.Status(401).JSON(fiber.Map{"error": "Token verification failed"})
|
||||||
}
|
}
|
||||||
|
|
||||||
googleUser := request.SigninWithGoogleDto{
|
googleUser := request.SigninWithGoogleDto{
|
||||||
@@ -364,7 +386,7 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
|
|||||||
|
|
||||||
res, err := h.service.SigninWithGoogle(ctx, &googleUser)
|
res, err := h.service.SigninWithGoogle(ctx, &googleUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(response.CommonResponse{
|
return c.Status(500).JSON(response.CommonResponse{
|
||||||
Status: false,
|
Status: false,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
})
|
})
|
||||||
@@ -386,5 +408,16 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
|
|||||||
SameSite: "None",
|
SameSite: "None",
|
||||||
})
|
})
|
||||||
|
|
||||||
return c.Redirect().To("http://localhost:5500")
|
allowed := map[string]bool{
|
||||||
|
"http://localhost:3000": true,
|
||||||
|
"http://localhost:5500": true,
|
||||||
|
"https://app.yourdomain.com": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectURL := data.RedirectURL
|
||||||
|
if !allowed[redirectURL] {
|
||||||
|
redirectURL = "http://localhost:3000"
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect().To(redirectURL)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,3 +7,8 @@ type TokenEntity struct {
|
|||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
TokenType constants.TokenType `json:"token_type"`
|
TokenType constants.TokenType `json:"token_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OAuthState struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
RedirectURL string `json:"redirect"`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user