@@ -60,6 +60,7 @@ describe('SpacecatJWTHandler', () => {
6060 logStub = {
6161 debug : sinon . stub ( ) ,
6262 info : sinon . stub ( ) ,
63+ warn : sinon . stub ( ) ,
6364 error : sinon . stub ( ) ,
6465 } ;
6566 handler = new SpacecatJWTHandler ( logStub ) ;
@@ -298,5 +299,39 @@ describe('SpacecatJWTHandler', () => {
298299 expect ( result ) . to . be . null ;
299300 expect ( logStub . debug . calledWith ( '[jwt] No bearer token provided' ) ) . to . be . true ;
300301 } ) ;
302+
303+ it ( 'returns null when token has both is_admin and is_read_only_admin' , async ( ) => {
304+ const token = await createToken ( createTokenPayload ( {
305+ user_id : 'test-user' ,
306+ is_admin : true ,
307+ is_read_only_admin : true ,
308+ tenants : [ ] ,
309+ } ) ) ;
310+ context . pathInfo = { headers : { authorization : `Bearer ${ token } ` } } ;
311+
312+ const result = await handler . checkAuth ( { } , context ) ;
313+
314+ expect ( result ) . to . be . null ;
315+ expect ( logStub . warn . calledWith ( '[jwt] Token has both is_admin and is_read_only_admin — rejecting' ) ) . to . be . true ;
316+ } ) ;
317+
318+ it ( 'successfully validates a token with is_read_only_admin and adds read_only_admin scope' , async ( ) => {
319+ const orgId = 'ro-org' ;
320+ const token = await createToken ( createTokenPayload ( {
321+ user_id : 'ro-user' ,
322+ is_admin : false ,
323+ is_read_only_admin : true ,
324+ tenants : [ { id : orgId , subServices : [ ] } ] ,
325+ } ) ) ;
326+ context . pathInfo = { headers : { authorization : `Bearer ${ token } ` } } ;
327+
328+ const result = await handler . checkAuth ( { } , context ) ;
329+
330+ expect ( result ) . to . be . instanceof ( AuthInfo ) ;
331+ expect ( result . isAdmin ( ) ) . to . be . false ;
332+ expect ( result . isReadOnlyAdmin ( ) ) . to . be . true ;
333+ expect ( result . hasScope ( 'read_only_admin' ) ) . to . be . true ;
334+ expect ( result . hasOrganization ( `${ orgId } @AdobeId` ) ) . to . be . true ;
335+ } ) ;
301336 } ) ;
302337} ) ;
0 commit comments