feat: enhance JWT error handling by returning unauthorized status for missing or malformed JWT
Build and Release / release (push) Successful in 1m54s

This commit is contained in:
2026-06-15 22:51:39 +07:00
parent 925935788a
commit 5f28663969
2 changed files with 71 additions and 99 deletions
+70 -98
View File
@@ -29,6 +29,60 @@ func NewAuthController(svc services.AuthService, oauth *oauth2.Config) *AuthCont
return &AuthController{service: svc, oauth: oauth} return &AuthController{service: svc, oauth: oauth}
} }
func authCookieSecure() bool {
return config.GetBoolConfigWithDefault("COOKIE_SECURE", true)
}
func authCookieDomain() string {
return config.GetConfigWithDefault("COOKIE_DOMAIN", "")
}
func authCookieSameSite() string {
if authCookieSecure() {
return "None"
}
return "Lax"
}
func setAuthCookie(c fiber.Ctx, name string, value string, duration time.Duration) {
cookie := &fiber.Cookie{
Name: name,
Value: value,
Expires: time.Now().Add(duration),
MaxAge: int(duration.Seconds()),
HTTPOnly: true,
Secure: authCookieSecure(),
SameSite: authCookieSameSite(),
Path: "/",
}
if domain := authCookieDomain(); domain != "" {
cookie.Domain = domain
}
c.Cookie(cookie)
}
func clearAuthCookie(c fiber.Ctx, name string) {
cookie := &fiber.Cookie{
Name: name,
Value: "",
Expires: time.Now().Add(-time.Hour),
MaxAge: -1,
HTTPOnly: true,
Secure: authCookieSecure(),
SameSite: authCookieSameSite(),
Path: "/",
}
if domain := authCookieDomain(); domain != "" {
cookie.Domain = domain
}
c.Cookie(cookie)
}
func setAuthCookies(c fiber.Ctx, res *response.AuthResponse) {
setAuthCookie(c, "access_token", res.AccessToken, constants.AccessTokenDuration)
setAuthCookie(c, "refresh_token", res.RefreshToken, constants.RefreshTokenDuration)
}
// Signin godoc // Signin godoc
// @Summary Sign in a user // @Summary Sign in a user
// @Description Authenticate user credentials and return access/refresh tokens // @Description Authenticate user credentials and return access/refresh tokens
@@ -61,25 +115,7 @@ func (h *AuthController) Signin(c fiber.Ctx) error {
}) })
} }
c.Cookie(&fiber.Cookie{ setAuthCookies(c, res)
Name: "access_token",
Value: res.AccessToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.AccessTokenDuration),
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: res.RefreshToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.RefreshTokenDuration),
})
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{ return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
Status: true, Status: true,
@@ -118,25 +154,7 @@ func (h *AuthController) Signup(c fiber.Ctx) error {
}) })
} }
c.Cookie(&fiber.Cookie{ setAuthCookies(c, res)
Name: "access_token",
Value: res.AccessToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.AccessTokenDuration),
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: res.RefreshToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.RefreshTokenDuration),
})
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{ return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
Status: true, Status: true,
@@ -184,25 +202,7 @@ func (h *AuthController) RefreshToken(c fiber.Ctx) error {
}) })
} }
c.Cookie(&fiber.Cookie{ setAuthCookies(c, res)
Name: "access_token",
Value: res.AccessToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.AccessTokenDuration),
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: res.RefreshToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.RefreshTokenDuration),
})
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{ return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
Status: true, Status: true,
@@ -348,15 +348,20 @@ func (h *AuthController) GoogleLogin(c fiber.Ctx) error {
b, _ := json.Marshal(data) b, _ := json.Marshal(data)
encoded := base64.URLEncoding.EncodeToString(b) encoded := base64.URLEncoding.EncodeToString(b)
c.Cookie(&fiber.Cookie{ oauthCookie := &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),
MaxAge: int((15 * time.Minute).Seconds()),
HTTPOnly: true, HTTPOnly: true,
Secure: true, Secure: authCookieSecure(),
SameSite: "None", SameSite: authCookieSameSite(),
Path: "/", Path: "/",
}) }
if domain := authCookieDomain(); domain != "" {
oauthCookie.Domain = domain
}
c.Cookie(oauthCookie)
url := h.oauth.AuthCodeURL(encoded) url := h.oauth.AuthCodeURL(encoded)
return c.Redirect().To(url) return c.Redirect().To(url)
@@ -393,7 +398,7 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
return c.Status(401).JSON(fiber.Map{"error": "Invalid state"}) return c.Status(401).JSON(fiber.Map{"error": "Invalid state"})
} }
c.ClearCookie("oauth_state") clearAuthCookie(c, "oauth_state")
code := c.Query("code") code := c.Query("code")
@@ -427,25 +432,7 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
}) })
} }
c.Cookie(&fiber.Cookie{ setAuthCookies(c, res)
Name: "access_token",
Value: res.AccessToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.AccessTokenDuration),
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: res.RefreshToken,
HTTPOnly: true,
Secure: true,
SameSite: "None",
Path: "/",
Expires: time.Now().Add(constants.RefreshTokenDuration),
})
allowed := map[string]bool{ allowed := map[string]bool{
"http://localhost:3000": true, "http://localhost:3000": true,
@@ -491,23 +478,8 @@ func (h *AuthController) Logout(c fiber.Ctx) error {
}) })
} }
c.Cookie(&fiber.Cookie{ clearAuthCookie(c, "access_token")
Name: "access_token", clearAuthCookie(c, "refresh_token")
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
Secure: true,
Path: "/",
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
Secure: true,
Path: "/",
})
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{ return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
Status: true, Status: true,
+1 -1
View File
@@ -134,7 +134,7 @@ func jwtSuccessRefresh() fiber.Handler {
func jwtError(c fiber.Ctx, err error) error { func jwtError(c fiber.Ctx, err error) error {
if err.Error() == "Missing or malformed JWT" { if err.Error() == "Missing or malformed JWT" {
return c.Status(fiber.StatusBadRequest). return c.Status(fiber.StatusUnauthorized).
JSON(response.CommonResponse{ JSON(response.CommonResponse{
Status: false, Status: false,
Message: "Missing or malformed JWT", Message: "Missing or malformed JWT",