@@ -37,6 +37,7 @@ describe("requireBearerAuth middleware", () => {
37
37
token : "valid-token" ,
38
38
clientId : "client-123" ,
39
39
scopes : [ "read" , "write" ] ,
40
+ expiresAt : Math . floor ( Date . now ( ) / 1000 ) + 3600 , // Token expires in an hour
40
41
} ;
41
42
mockVerifyAccessToken . mockResolvedValue ( validAuthInfo ) ;
42
43
@@ -53,13 +54,17 @@ describe("requireBearerAuth middleware", () => {
53
54
expect ( mockResponse . status ) . not . toHaveBeenCalled ( ) ;
54
55
expect ( mockResponse . json ) . not . toHaveBeenCalled ( ) ;
55
56
} ) ;
56
-
57
- it ( "should reject expired tokens" , async ( ) => {
57
+
58
+ it . each ( [
59
+ [ 100 ] , // Token expired 100 seconds ago
60
+ [ 0 ] , // Token expires at the same time as now
61
+ ] ) ( "should reject expired tokens (expired %s seconds ago)" , async ( expiredSecondsAgo : number ) => {
62
+ const expiresAt = Math . floor ( Date . now ( ) / 1000 ) - expiredSecondsAgo ;
58
63
const expiredAuthInfo : AuthInfo = {
59
64
token : "expired-token" ,
60
65
clientId : "client-123" ,
61
66
scopes : [ "read" , "write" ] ,
62
- expiresAt : Math . floor ( Date . now ( ) / 1000 ) - 100 , // Token expired 100 seconds ago
67
+ expiresAt
63
68
} ;
64
69
mockVerifyAccessToken . mockResolvedValue ( expiredAuthInfo ) ;
65
70
@@ -82,6 +87,37 @@ describe("requireBearerAuth middleware", () => {
82
87
expect ( nextFunction ) . not . toHaveBeenCalled ( ) ;
83
88
} ) ;
84
89
90
+ it . each ( [
91
+ [ undefined ] , // Token has no expiration time
92
+ [ NaN ] , // Token has no expiration time
93
+ ] ) ( "should reject tokens with no expiration time (expiresAt: %s)" , async ( expiresAt : number | undefined ) => {
94
+ const noExpirationAuthInfo : AuthInfo = {
95
+ token : "no-expiration-token" ,
96
+ clientId : "client-123" ,
97
+ scopes : [ "read" , "write" ] ,
98
+ expiresAt
99
+ } ;
100
+ mockVerifyAccessToken . mockResolvedValue ( noExpirationAuthInfo ) ;
101
+
102
+ mockRequest . headers = {
103
+ authorization : "Bearer expired-token" ,
104
+ } ;
105
+
106
+ const middleware = requireBearerAuth ( { verifier : mockVerifier } ) ;
107
+ await middleware ( mockRequest as Request , mockResponse as Response , nextFunction ) ;
108
+
109
+ expect ( mockVerifyAccessToken ) . toHaveBeenCalledWith ( "expired-token" ) ;
110
+ expect ( mockResponse . status ) . toHaveBeenCalledWith ( 401 ) ;
111
+ expect ( mockResponse . set ) . toHaveBeenCalledWith (
112
+ "WWW-Authenticate" ,
113
+ expect . stringContaining ( 'Bearer error="invalid_token"' )
114
+ ) ;
115
+ expect ( mockResponse . json ) . toHaveBeenCalledWith (
116
+ expect . objectContaining ( { error : "invalid_token" , error_description : "Token has no expiration time" } )
117
+ ) ;
118
+ expect ( nextFunction ) . not . toHaveBeenCalled ( ) ;
119
+ } ) ;
120
+
85
121
it ( "should accept non-expired tokens" , async ( ) => {
86
122
const nonExpiredAuthInfo : AuthInfo = {
87
123
token : "valid-token" ,
@@ -141,6 +177,7 @@ describe("requireBearerAuth middleware", () => {
141
177
token : "valid-token" ,
142
178
clientId : "client-123" ,
143
179
scopes : [ "read" , "write" , "admin" ] ,
180
+ expiresAt : Math . floor ( Date . now ( ) / 1000 ) + 3600 , // Token expires in an hour
144
181
} ;
145
182
mockVerifyAccessToken . mockResolvedValue ( authInfo ) ;
146
183
0 commit comments