@@ -188,3 +188,99 @@ func TestProtectedResourceMetadataHandler(t *testing.T) {
188188 })
189189 }
190190}
191+
192+ func TestRequireBearerToken (t * testing.T ) {
193+ verifier := func (_ context.Context , token string , _ * http.Request ) (* TokenInfo , error ) {
194+ if token == "valid" {
195+ return & TokenInfo {Expiration : time .Now ().Add (time .Hour ), Scopes : []string {"read" }}, nil
196+ }
197+ return nil , ErrInvalidToken
198+ }
199+
200+ tests := []struct {
201+ name string
202+ opts * RequireBearerTokenOptions
203+ authHeader string
204+ wantHeader string
205+ wantStatus int
206+ }{
207+ {
208+ name : "no middleware options" ,
209+ opts : nil ,
210+ authHeader : "Bearer invalid" ,
211+ wantHeader : "" ,
212+ wantStatus : http .StatusUnauthorized ,
213+ },
214+ {
215+ name : "metadata only" ,
216+ opts : & RequireBearerTokenOptions {
217+ ResourceMetadataURL : "https://example.com/resource-metadata" ,
218+ },
219+ authHeader : "Bearer invalid" ,
220+ wantHeader : "Bearer resource_metadata=\" https://example.com/resource-metadata\" " ,
221+ wantStatus : http .StatusUnauthorized ,
222+ },
223+ {
224+ name : "scopes only" ,
225+ opts : & RequireBearerTokenOptions {
226+ Scopes : []string {"read" , "write" },
227+ },
228+ authHeader : "Bearer invalid" ,
229+ wantHeader : "Bearer scope=\" read write\" " ,
230+ wantStatus : http .StatusUnauthorized ,
231+ },
232+ {
233+ name : "metadata and scopes" ,
234+ opts : & RequireBearerTokenOptions {
235+ ResourceMetadataURL : "https://example.com/resource-metadata" ,
236+ Scopes : []string {"read" , "write" },
237+ },
238+ authHeader : "Bearer invalid" ,
239+ wantHeader : "Bearer resource_metadata=\" https://example.com/resource-metadata\" , scope=\" read write\" " ,
240+ wantStatus : http .StatusUnauthorized ,
241+ },
242+ {
243+ name : "insufficient scope" ,
244+ opts : & RequireBearerTokenOptions {
245+ Scopes : []string {"admin" },
246+ },
247+ authHeader : "Bearer valid" , // Has "read", needs "admin" -> 403
248+ wantHeader : "Bearer scope=\" admin\" " ,
249+ wantStatus : http .StatusForbidden ,
250+ },
251+ {
252+ name : "success" ,
253+ opts : & RequireBearerTokenOptions {
254+ Scopes : []string {"read" },
255+ },
256+ authHeader : "Bearer valid" ,
257+ wantHeader : "" ,
258+ wantStatus : http .StatusOK ,
259+ },
260+ }
261+
262+ for _ , tt := range tests {
263+ t .Run (tt .name , func (t * testing.T ) {
264+ handler := RequireBearerToken (verifier , tt .opts )(http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
265+ w .WriteHeader (http .StatusOK )
266+ }))
267+
268+ req := httptest .NewRequest ("GET" , "/" , nil )
269+ if tt .authHeader != "" {
270+ req .Header .Set ("Authorization" , tt .authHeader )
271+ }
272+ rec := httptest .NewRecorder ()
273+
274+ handler .ServeHTTP (rec , req )
275+
276+ if rec .Code != tt .wantStatus {
277+ t .Errorf ("status = %d, want %d" , rec .Code , tt .wantStatus )
278+ }
279+
280+ got := rec .Header ().Get ("WWW-Authenticate" )
281+ if got != tt .wantHeader {
282+ t .Errorf ("WWW-Authenticate = %q, want %q" , got , tt .wantHeader )
283+ }
284+ })
285+ }
286+ }
0 commit comments