Skip to content

Commit 7b8fd2f

Browse files
test(middleware): cover AuthErrorInvalidClaims branch (patch coverage)
auth.go lines 528-529 are reached when a JWT with valid signature has empty uid OR tid claims — the InvalidClaims arm added in PR #178 for BUG-API-051 sub-codes. Existing strict tests cover Garbage/Expired/ WrongSecret/NonBearer but never construct a valid-sig + empty-claim combination. Three subcases added: empty tid, empty uid, both empty. All three must 401 in OptionalAuthStrict mode. Verified locally: all 3 tests PASS; coverprofile shows lines 528-529 hit count = 1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 34a17cc commit 7b8fd2f

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package middleware_test
2+
3+
// optional_auth_strict_invalid_claims_test.go — patch-coverage backfill
4+
// for the AuthErrorInvalidClaims branch added in PR #178 (BUG-API-051).
5+
//
6+
// auth.go: a token whose signature is valid AND `parsed.Valid` is true but
7+
// either `UserID` or `TeamID` claim is empty falls through to:
8+
// reason = AuthErrorInvalidClaims
9+
// That branch is reached only when the JWT is well-formed enough to pass
10+
// jwt-go's parse but still missing required claims. Existing strict tests
11+
// cover Garbage, Expired, WrongSecret, NonBearer; none constructs a valid
12+
// signature with empty uid/tid.
13+
14+
import (
15+
"net/http"
16+
"net/http/httptest"
17+
"testing"
18+
"time"
19+
20+
"github.com/gofiber/fiber/v2"
21+
jwt "github.com/golang-jwt/jwt/v5"
22+
"github.com/google/uuid"
23+
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
25+
26+
"instant.dev/internal/testhelpers"
27+
)
28+
29+
// signSessionEmptyTeam returns a JWT with valid signature + valid exp but
30+
// `tid` (team_id) blank — exercises the InvalidClaims arm.
31+
func signSessionEmptyTeam(t *testing.T, secret, userID string) string {
32+
t.Helper()
33+
claims := jwt.MapClaims{
34+
"uid": userID,
35+
"tid": "",
36+
"jti": uuid.NewString(),
37+
"iat": time.Now().Unix(),
38+
"exp": time.Now().Add(time.Hour).Unix(),
39+
}
40+
tok, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
41+
require.NoError(t, err)
42+
return tok
43+
}
44+
45+
// signSessionEmptyUID returns a JWT with valid signature but empty uid.
46+
func signSessionEmptyUID(t *testing.T, secret, teamID string) string {
47+
t.Helper()
48+
claims := jwt.MapClaims{
49+
"uid": "",
50+
"tid": teamID,
51+
"jti": uuid.NewString(),
52+
"iat": time.Now().Unix(),
53+
"exp": time.Now().Add(time.Hour).Unix(),
54+
}
55+
tok, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
56+
require.NoError(t, err)
57+
return tok
58+
}
59+
60+
// TestOptionalAuthStrict_EmptyTeamID_InvalidClaims — valid signature, empty
61+
// `tid` → 401 in strict mode.
62+
func TestOptionalAuthStrict_EmptyTeamID_InvalidClaims(t *testing.T) {
63+
tok := signSessionEmptyTeam(t, testhelpers.TestJWTSecret, uuid.NewString())
64+
app := newOptionalAuthStrictApp(testhelpers.TestJWTSecret)
65+
req := httptest.NewRequest(http.MethodGet, "/test", nil)
66+
req.Header.Set("Authorization", "Bearer "+tok)
67+
68+
resp, err := app.Test(req, 1000)
69+
require.NoError(t, err)
70+
defer resp.Body.Close()
71+
72+
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode,
73+
"valid-sig but empty tid must 401 in strict mode (InvalidClaims branch)")
74+
}
75+
76+
// TestOptionalAuthStrict_EmptyUserID_InvalidClaims — valid signature, empty
77+
// `uid` → 401 in strict mode.
78+
func TestOptionalAuthStrict_EmptyUserID_InvalidClaims(t *testing.T) {
79+
tok := signSessionEmptyUID(t, testhelpers.TestJWTSecret, uuid.NewString())
80+
app := newOptionalAuthStrictApp(testhelpers.TestJWTSecret)
81+
req := httptest.NewRequest(http.MethodGet, "/test", nil)
82+
req.Header.Set("Authorization", "Bearer "+tok)
83+
84+
resp, err := app.Test(req, 1000)
85+
require.NoError(t, err)
86+
defer resp.Body.Close()
87+
88+
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode,
89+
"valid-sig but empty uid must 401 in strict mode (InvalidClaims branch)")
90+
}
91+
92+
// TestOptionalAuthStrict_BothEmpty_InvalidClaims — both empty → still 401.
93+
func TestOptionalAuthStrict_BothEmpty_InvalidClaims(t *testing.T) {
94+
claims := jwt.MapClaims{
95+
"uid": "",
96+
"tid": "",
97+
"jti": uuid.NewString(),
98+
"iat": time.Now().Unix(),
99+
"exp": time.Now().Add(time.Hour).Unix(),
100+
}
101+
tok, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(testhelpers.TestJWTSecret))
102+
require.NoError(t, err)
103+
104+
app := newOptionalAuthStrictApp(testhelpers.TestJWTSecret)
105+
req := httptest.NewRequest(http.MethodGet, "/test", nil)
106+
req.Header.Set("Authorization", "Bearer "+tok)
107+
108+
resp, err := app.Test(req, 1000)
109+
require.NoError(t, err)
110+
defer resp.Body.Close()
111+
112+
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode,
113+
"valid-sig with both empty claims must 401")
114+
}

0 commit comments

Comments
 (0)