@@ -23,7 +23,7 @@ export class AuthGuard implements CanActivate {
2323 if ( isPublic ) return true ;
2424
2525 const req = context . switchToHttp ( ) . getRequest ( ) ;
26- const isM2M = this . reflector . getAllAndOverride < boolean > ( IS_M2M_KEY , [
26+ const routeM2MOnly = this . reflector . getAllAndOverride < boolean > ( IS_M2M_KEY , [
2727 context . getHandler ( ) ,
2828 context . getClass ( ) ,
2929 ] ) ;
@@ -36,24 +36,45 @@ export class AuthGuard implements CanActivate {
3636 } ;
3737 }
3838
39- // Regular authentication - check that we have user's email and have verified the id token
40- if ( ! isM2M ) {
39+ const tokenIsM2M = Boolean ( req . m2mTokenScope ) ;
40+
41+ // If route explicitly requires M2M, enforce M2M + scope
42+ if ( routeM2MOnly ) {
43+ if ( ! req . idTokenVerified || ! tokenIsM2M ) {
44+ throw new UnauthorizedException ( ) ;
45+ }
46+
47+ const allowedM2mScopes = this . reflector . getAllAndOverride < M2mScope [ ] > (
48+ SCOPES_KEY ,
49+ [ context . getHandler ( ) , context . getClass ( ) ] ,
50+ ) ;
51+ const reqScopes = String ( req . m2mTokenScope || '' ) . split ( ' ' ) ;
52+ return reqScopes . some ( ( s ) => allowedM2mScopes . includes ( s as M2mScope ) ) ;
53+ }
54+
55+ // Hybrid (default) route behavior: allow either
56+ // - Verified user JWT (email present), OR
57+ // - Verified M2M token but only if scope matches when scopes are declared on the route
58+
59+ // User JWT branch
60+ if ( ! tokenIsM2M ) {
4161 return Boolean ( req . email && req . idTokenVerified ) ;
4262 }
4363
44- // M2M authentication - check scopes
45- if ( ! req . idTokenVerified || ! req . m2mTokenScope )
64+ // M2M branch on non-M2M-only route: require declared scopes, otherwise deny
65+ if ( ! req . idTokenVerified ) {
4666 throw new UnauthorizedException ( ) ;
67+ }
4768
4869 const allowedM2mScopes = this . reflector . getAllAndOverride < M2mScope [ ] > (
4970 SCOPES_KEY ,
5071 [ context . getHandler ( ) , context . getClass ( ) ] ,
5172 ) ;
52-
53- const reqScopes = req . m2mTokenScope . split ( ' ' ) ;
54- if ( reqScopes . some ( ( reqScope ) => allowedM2mScopes . includes ( reqScope ) ) ) {
55- return true ;
73+ if ( ! allowedM2mScopes || allowedM2mScopes . length === 0 ) {
74+ // No scopes declared for this route, do not allow M2M by default
75+ return false ;
5676 }
57- return false ;
77+ const reqScopes = String ( req . m2mTokenScope || '' ) . split ( ' ' ) ;
78+ return reqScopes . some ( ( s ) => allowedM2mScopes . includes ( s as M2mScope ) ) ;
5879 }
5980}
0 commit comments