# Authentication Audit - 20251123-124317 == JWT Implementation == /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:20: "github.com/golang-jwt/jwt/v5" /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:163: jwtSecret []byte /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:277: jwtSecret = []byte(strings.TrimSpace(os.Getenv("JWT_SECRET"))) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:278: if len(jwtSecret) < 32 { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:279: log.Fatal("JWT_SECRET must be set and at least 32 characters") /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:308: tokenString := strings.TrimPrefix(authHeader, "Bearer ") /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:309: if tokenString == authHeader { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:314: token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:315: if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:318: return jwtSecret, nil /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:321: if err != nil || !token.Valid { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:322: http.Error(w, "Invalid or expired token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:326: claims, ok := token.Claims.(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:328: http.Error(w, "Invalid token claims", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:345: tokenString := strings.TrimPrefix(authHeader, "Bearer ") /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:346: if tokenString == authHeader { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:351: token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:352: if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:355: return jwtSecret, nil /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:358: if err != nil || !token.Valid { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:363: claims, ok := token.Claims.(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:376: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:396:func extractRoles(claims jwt.MapClaims) ([]string, error) { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:420:func hasRole(claims jwt.MapClaims, role string) bool { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:437:func getUserID(claims jwt.MapClaims) int { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:447:func getUserName(claims jwt.MapClaims) string { /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:660: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:700: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:744: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:783: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:849: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:893: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:933: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:979: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:1006: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:1060: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:1113: claims := r.Context().Value(userContextKey).(jwt.MapClaims) /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:20: "github.com/golang-jwt/jwt/v5" /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:111:// PaymentToken represents a whitelisted ERC-20 token. /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:116: TokenSymbol string `json:"tokenSymbol"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:117: TokenName string `json:"tokenName"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:156: TokenID *int `json:"tokenId"` // NULL for native currency /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:165: TokenSymbol *string `json:"tokenSymbol"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:226: TokenID *int `json:"tokenId"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:242: TokenID *int `json:"tokenId"` // For crypto tokens /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:258:// TokenWhitelistRequest for admin token management. /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:262: TokenSymbol string `json:"tokenSymbol"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:263: TokenName string `json:"tokenName"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:293: AccessToken string `json:"access_token"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:294: TokenType string `json:"token_type"` == Token Expiration Settings == /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:316: return nil, fmt.Errorf("unexpected signing method") /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:322: http.Error(w, "Invalid or expired token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/forum-service/main.go:353: return nil, fmt.Errorf("unexpected signing method") /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main_test.go:27: expected := "ok\n" /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main_test.go:28: if rr.Body.String() != expected { /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main_test.go:29: t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:101: ExplorerURL *string `json:"explorerUrl"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:102: ExplorerTxPath *string `json:"explorerTxPath"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:169: ExplorerURL string `json:"explorerUrl"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:170: ExpiresAt string `json:"expiresAt"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:295: ExpiresIn int `json:"expires_in"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:526: return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1406: explorer_url, explorer_tx_path, is_testnet, is_enabled, min_confirmations, avg_block_time, /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1553: explorer_url, min_confirmations, is_enabled /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1716: explorerURL := "" /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1718: explorerURL = *network.ExplorerURL /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1729: ExplorerURL: explorerURL, /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1730: ExpiresAt: time.Now().Add(30 * time.Minute).Format(time.RFC3339), /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1892: ExplorerURL *string `json:"explorerUrl"` /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:1898: n.network_code, n.explorer_url /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:2609: return nil, fmt.Errorf("unexpected signing method") /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:2837: paypalTokenExpiry time.Time /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:2859: if paypalAccessToken != "" && time.Now().Before(paypalTokenExpiry) { /home/administrator/projects/coppertone.tech/backend/functions/payment-service/main.go:2889: paypalTokenExpiry = time.Now().Add(time.Duration(token.ExpiresIn-60) * time.Second) // Expire 60s early /home/administrator/projects/coppertone.tech/backend/functions/work-management-service/main_test.go:27: expected := "ok\n" /home/administrator/projects/coppertone.tech/backend/functions/work-management-service/main_test.go:28: if rr.Body.String() != expected { /home/administrator/projects/coppertone.tech/backend/functions/work-management-service/main_test.go:29: t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) /home/administrator/projects/coppertone.tech/backend/functions/work-management-service/main.go:383: return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:117: expectedStatus int /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:118: expectedError string /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:123: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:124: expectedError: "Email is required", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:129: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:130: expectedError: "Invalid email format", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:135: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:136: expectedError: "Password must be at least 8 characters", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:141: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:142: expectedError: "uppercase", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:147: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:148: expectedError: "Name is required", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:161: if rr.Code != tt.expectedStatus { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:162: t.Errorf("handler returned wrong status code: got %v want %v", rr.Code, tt.expectedStatus) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:165: if tt.expectedError != "" && !strings.Contains(rr.Body.String(), tt.expectedError) { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:166: t.Errorf("handler returned unexpected body: got %v, want to contain %v", rr.Body.String(), tt.expectedError) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:183: expectedStatus int /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:188: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:193: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:198: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:211: if rr.Code != tt.expectedStatus { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:212: t.Errorf("handler returned wrong status code: got %v want %v", rr.Code, tt.expectedStatus) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:224: expectedStatus int /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:231: expectedStatus: http.StatusMethodNotAllowed, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:238: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:256: if rr.Code != tt.expectedStatus { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:257: t.Errorf("handler returned wrong status code: got %v want %v", rr.Code, tt.expectedStatus) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:269: expectedStatus int /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:276: expectedStatus: http.StatusMethodNotAllowed, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:283: expectedStatus: http.StatusBadRequest, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:301: if rr.Code != tt.expectedStatus { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:302: t.Errorf("handler returned wrong status code: got %v want %v", rr.Code, tt.expectedStatus) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:399: // This will fail if JWT_SECRET is not set, which is expected in test environment /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:403: // If JWT_SECRET is not set, we expect an error /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:16: "regexp" /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:37:// Token expiration configuration /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:39: accessTokenExpiry = 15 * time.Minute // Short-lived access tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:40: refreshTokenExpiry = 7 * 24 * time.Hour // 7 day refresh tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:87: // Reset window if expired /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:118: // Reset window if expired /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:176:var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:316: ExpiresIn int64 `json:"expiresIn"` // Access token expiry in seconds /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:527: // Default to restrictive in production - set CORS_ALLOW_ORIGIN explicitly /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:974: http.Error(w, "Invalid or expired refresh token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1341: return nil, fmt.Errorf("unexpected signing method") /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1347: http.Error(w, "Invalid or expired token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1412: // Verify Origin header matches expected origin (additional CSRF protection) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1421: log.Printf("SECURITY: Origin mismatch for user %d: expected %s, got %s", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1463: "exp": time.Now().Add(accessTokenExpiry).Unix(), /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1485: expiresAt := time.Now().Add(refreshTokenExpiry) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1489: INSERT INTO refresh_tokens (user_id, token_hash, expires_at, client_ip, created_at) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1491: `, userID, string(tokenHash), expiresAt, clientIP) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1496: log.Printf("AUDIT: Refresh token created for user_id %d from IP %s, expires %s", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1497: userID, clientIP, expiresAt.Format(time.RFC3339)) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1504: // Get all non-expired tokens and check against provided token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1508: WHERE expires_at > NOW() AND revoked_at IS NULL /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1528: return 0, 0, errors.New("invalid or expired refresh token") /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1576: expiresAt := time.Now().Add(accessTokenExpiry) // CSRF token expires with access token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1580: INSERT INTO csrf_tokens (user_id, token_hash, expires_at, client_ip, created_at) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1582: `, userID, string(tokenHash), expiresAt, clientIP) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1596: // Get all non-expired tokens for this user and check against provided token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1600: WHERE user_id = $1 AND expires_at > NOW() /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1623:// cleanupExpiredCSRFTokens removes expired CSRF tokens (call periodically) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1624:func cleanupExpiredCSRFTokens() { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1625: result, err := db.Exec(`DELETE FROM csrf_tokens WHERE expires_at < NOW()`) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1627: log.Printf("Error cleaning up expired CSRF tokens: %v", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1632: log.Printf("Cleaned up %d expired CSRF tokens", rowsAffected) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1670: ExpiresIn: int64(accessTokenExpiry.Seconds()), /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1700: return nil, errors.New("roles claim has unexpected type") /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1747: "exp": time.Now().Add(time.Hour).Unix(), /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:374: return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:380: http.Error(w, "Invalid or expired token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:591: // Don't expose review details to public /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:636: // Don't expose review details to public /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:1168: // Don't expose internal details to public /home/administrator/projects/coppertone.tech/backend/functions/blog-service/main.go:1213: // Don't expose internal details to public /home/administrator/projects/coppertone.tech/backend/functions/contact-service/main.go:13: "regexp" /home/administrator/projects/coppertone.tech/backend/functions/contact-service/main.go:357: return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) /home/administrator/projects/coppertone.tech/backend/functions/contact-service/main.go:650: emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`) == Password Hashing == /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:26: "golang.org/x/crypto/bcrypt" /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:171: maxPasswordLength = 72 // bcrypt limit /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:632: passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:861: if err := bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(req.Password)); err != nil { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1101: passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1480: tokenHash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1523: if bcrypt.CompareHashAndPassword([]byte(tokenHash), []byte(token)) == nil { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1571: tokenHash, err := bcrypt.GenerateFromPassword([]byte(csrfToken), bcrypt.DefaultCost) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1615: if bcrypt.CompareHashAndPassword([]byte(tokenHash), []byte(token)) == nil { /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1753: hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1761: return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil == Weak Hashing (MD5, SHA1) == None found - good == Session Management == /home/administrator/projects/coppertone.tech/frontend/src/stores/trustBusiness.ts:865: options: ['Terms of Use', 'Privacy Policy', 'Cookie Policy', 'Refund Policy', 'Shipping Policy'], /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:75: 'session expired': { /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:77: message: 'Your session has expired. Please sign in again.' /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:90: message: 'Your session may have expired. Please sign in again.' /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/types.ts:69: * If `false`, will also ignore cookies in the CORS response. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/types.ts:149: * a CORS request, _OR_ when cookies are to be ignored by the CORS response, set to `false`. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/types.ts:156: * The name of your site's XSRF cookie. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/types.ts:158: xsrfCookieName?: string; /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/types.ts:161: * The name of a custom header that you can use to send your XSRF cookie. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:370: // Allow users to provide their XSRF cookie name and the name of a custom header to use to /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:371: // send the cookie. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:372: const { withCredentials, xsrfCookieName, xsrfHeaderName } = config; /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:373: if ((withCredentials || !crossDomain) && xsrfCookieName && xsrfHeaderName) { /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:374: const xsrfCookie = document?.cookie.match(new RegExp(`(^|;\\s*)(${xsrfCookieName})=([^;]*)`))?.pop() ?? ''; /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:375: if (xsrfCookie) { /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/src/internal/ajax/ajax.ts:376: headers[xsrfHeaderName] = xsrfCookie; /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/dist/types/internal/ajax/types.d.ts:56: * If `false`, will also ignore cookies in the CORS response. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/dist/types/internal/ajax/types.d.ts:125: * a CORS request, _OR_ when cookies are to be ignored by the CORS response, set to `false`. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/dist/types/internal/ajax/types.d.ts:131: * The name of your site's XSRF cookie. /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/dist/types/internal/ajax/types.d.ts:133: xsrfCookieName?: string; /home/administrator/projects/coppertone.tech/frontend/node_modules/rxjs/dist/types/internal/ajax/types.d.ts:135: * The name of a custom header that you can use to send your XSRF cookie. /home/administrator/projects/coppertone.tech/frontend/node_modules/globals/index.d.ts:922: readonly 'sessionStorage': false; /home/administrator/projects/coppertone.tech/frontend/node_modules/axios/index.d.ts:77: getSetCookie(): string[]; /home/administrator/projects/coppertone.tech/frontend/node_modules/axios/index.d.ts:99: "set-cookie": string[]; /home/administrator/projects/coppertone.tech/frontend/node_modules/axios/index.d.ts:336: xsrfCookieName?: string; /home/administrator/projects/coppertone.tech/frontend/node_modules/axios/index.d.ts:374: sessionTimeout?: number; /home/administrator/projects/coppertone.tech/frontend/node_modules/ansi-escapes/index.d.ts:11: - `N%`: N percent of the session's width or height. /home/administrator/projects/coppertone.tech/frontend/node_modules/ansi-escapes/index.d.ts:21: - `N%`: N percent of the session's width or height. /home/administrator/projects/coppertone.tech/frontend/node_modules/log-update/index.d.ts:38: Persist the logged output. Useful if you want to start a new log session below the current one. /home/administrator/projects/coppertone.tech/frontend/node_modules/tough-cookie/dist/getPublicSuffix.d.ts:11: * In testing scenarios it's common to configure the cookie store with so that `http://localhost` can be used as a domain: == Refresh Token Implementation == /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:177: refreshToken: string /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:188: const refreshToken = ref(localStorage.getItem('refresh_token')) /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:219: refreshToken.value = response.refreshToken /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:226: localStorage.setItem('refresh_token', response.refreshToken) /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:234: refreshToken.value = null /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:238: localStorage.removeItem('refresh_token') /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:249: // Refresh the access token using the refresh token /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:256: if (!refreshToken.value) { /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:265: body: JSON.stringify({ refreshToken: refreshToken.value }) /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:546: // Call backend to revoke refresh token /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:547: if (refreshToken.value) { /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:552: body: JSON.stringify({ refreshToken: refreshToken.value }) /home/administrator/projects/coppertone.tech/frontend/src/stores/auth.ts:604: refreshToken, /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:218:// TestRefreshTokenValidation tests refresh token endpoint validation (non-DB tests only) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:235: name: "missing refresh token", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main_test.go:280: name: "missing refresh token", /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:40: refreshTokenExpiry = 7 * 24 * time.Hour // 7 day refresh tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:41: refreshTokenLength = 32 // 256-bit refresh token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:306:// RefreshTokenRequest for refreshing access tokens. /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:308: RefreshToken string `json:"refreshToken"` /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:311:// AuthTokenResponse includes both access and refresh tokens. /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:314: RefreshToken string `json:"refreshToken"` /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:320:// LogoutRequest for revoking refresh tokens. /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:322: RefreshToken string `json:"refreshToken"` /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:950:// handleRefreshToken exchanges a valid refresh token for a new access token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:970: // Validate the refresh token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:973: log.Printf("SECURITY: Invalid refresh token attempt from IP %s: %v", clientIP, err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:974: http.Error(w, "Invalid or expired refresh token", http.StatusUnauthorized) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:978: // Revoke the old refresh token (rotation for security) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:980: log.Printf("Warning: Failed to revoke old refresh token: %v", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:987: http.Error(w, "Failed to refresh tokens", http.StatusInternalServerError) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:997:// handleLogout revokes a specific refresh token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1027: // Revoke the refresh token /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1029: log.Printf("Error revoking refresh token: %v", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1040:// handleLogoutAll revokes all refresh tokens for the authenticated user /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1052: log.Printf("Error revoking all refresh tokens for user %d: %v", userID, err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1470:// generateRefreshToken creates a secure random refresh token and stores it in the database /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1473: tokenBytes := make([]byte, refreshTokenLength) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1482: return "", fmt.Errorf("failed to hash refresh token: %w", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1485: expiresAt := time.Now().Add(refreshTokenExpiry) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1489: INSERT INTO refresh_tokens (user_id, token_hash, expires_at, client_ip, created_at) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1493: return "", fmt.Errorf("failed to store refresh token: %w", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1502:// validateRefreshToken validates a refresh token and returns the user ID /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1507: FROM refresh_tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1511: return 0, 0, fmt.Errorf("failed to query refresh tokens: %w", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1528: return 0, 0, errors.New("invalid or expired refresh token") /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1531:// revokeRefreshToken marks a refresh token as revoked /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1534: UPDATE refresh_tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1541:// revokeAllUserRefreshTokens revokes all refresh tokens for a user /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1544: UPDATE refresh_tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1553: log.Printf("AUDIT: Revoked %d refresh tokens for user_id %d", rowsAffected, userID) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1642:// generateTokenPair creates access, refresh, and CSRF tokens /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1649: refreshToken, err := generateRefreshToken(userID, clientIP) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1651: return nil, fmt.Errorf("failed to generate refresh token: %w", err) /home/administrator/projects/coppertone.tech/backend/functions/auth-service/main.go:1668: RefreshToken: refreshToken,