88logger = logging .getLogger (__name__ )
99
1010
11- def _verify_access_token_if_present (
11+ def _verify_access_token (
1212 access_token : str | None , tenant_id : str | None = None
1313) -> dict | None :
14- """Verify Microsoft access token and return claims if valid, None otherwise."""
14+ """
15+ Verify Microsoft access token signature, expiry, audience, and issuer domain.
16+
17+ Returns the verified claims dict on success.
18+ Raises JWTVerificationError (or a subclass) if verification fails — callers
19+ must NOT proceed with a token that fails this check.
20+ Returns None only when no token is present or verification is not configured.
21+ """
1522 if not access_token :
1623 return None
1724
1825 raw_token = access_token .removeprefix ("Bearer " ).strip ()
19- try :
20- from config .settings import MICROSOFT_GRAPH_OAUTH_CLIENT_ID
21- from utils .jwt_verification import JWTVerificationError , verify_microsoft_access_token
2226
23- if not MICROSOFT_GRAPH_OAUTH_CLIENT_ID :
24- logger .warning (
25- "MICROSOFT_GRAPH_OAUTH_CLIENT_ID not configured - skipping access token verification"
26- )
27- return None
27+ from config .settings import MICROSOFT_ALLOWED_TENANT_IDS , MICROSOFT_GRAPH_OAUTH_CLIENT_ID
28+ from utils .jwt_verification import JWTVerificationError , verify_microsoft_access_token
2829
29- # Verify token with FULL validation
30- claims = verify_microsoft_access_token (
31- raw_token , MICROSOFT_GRAPH_OAUTH_CLIENT_ID , tenant_id = tenant_id
30+ if not MICROSOFT_GRAPH_OAUTH_CLIENT_ID :
31+ logger . warning (
32+ " MICROSOFT_GRAPH_OAUTH_CLIENT_ID not configured - skipping access token verification"
3233 )
33- logger .debug ("Microsoft access token verification successful, tenant=%s" , claims .get ("tid" ))
34- return claims
35-
36- except JWTVerificationError as e :
37- logger .warning ("Microsoft access token verification failed: %s" , str (e ))
38- except Exception as e :
39- logger .error ("Unexpected error verifying Microsoft access token: %s" , str (e ))
34+ return None
4035
41- return None
36+ # Raises JWTVerificationError on any failure — intentionally not caught here
37+ # so that callers (get_access_token, get_access_token_for_resource) propagate
38+ # the error and refuse to return an unverified token.
39+ claims = verify_microsoft_access_token (
40+ raw_token ,
41+ MICROSOFT_GRAPH_OAUTH_CLIENT_ID ,
42+ tenant_id = tenant_id ,
43+ allowed_tenant_ids = MICROSOFT_ALLOWED_TENANT_IDS ,
44+ )
45+ logger .debug ("SharePoint access token verified, tenant=%s" , claims .get ("tid" ))
46+ return claims
4247
4348
4449class SharePointOAuth :
@@ -396,12 +401,7 @@ def get_access_token(self) -> str:
396401 )
397402 if result and "access_token" in result :
398403 access_token = result ["access_token" ]
399- # Verify token (security enhancement)
400- claims = _verify_access_token_if_present (access_token )
401- if claims :
402- logger .debug (
403- "SharePoint access token verified, tenant=%s" , claims .get ("tid" )
404- )
404+ _verify_access_token (access_token ) # raises JWTVerificationError on failure
405405 logger .info ("SharePoint get_access_token: Success with current account" )
406406 return access_token
407407 else :
@@ -414,10 +414,7 @@ def get_access_token(self) -> str:
414414 result = self .app .acquire_token_silent (self .RESOURCE_SCOPES , account = None )
415415 if result and "access_token" in result :
416416 access_token = result ["access_token" ]
417- # Verify token (security enhancement)
418- claims = _verify_access_token_if_present (access_token )
419- if claims :
420- logger .debug ("SharePoint access token verified, tenant=%s" , claims .get ("tid" ))
417+ _verify_access_token (access_token ) # raises JWTVerificationError on failure
421418 logger .info ("SharePoint get_access_token: Fallback success" )
422419 return access_token
423420
@@ -465,12 +462,7 @@ def get_access_token_for_resource(self, resource_url: str) -> str:
465462 )
466463 if result and "access_token" in result :
467464 access_token = result ["access_token" ]
468- # Verify token (security enhancement) - note: resource tokens may have different audience
469- claims = _verify_access_token_if_present (access_token )
470- if claims :
471- logger .debug (
472- "SharePoint resource token verified, tenant=%s" , claims .get ("tid" )
473- )
465+ _verify_access_token (access_token ) # raises JWTVerificationError on failure
474466 logger .info (
475467 "SharePoint get_access_token_for_resource: Success with current account"
476468 )
@@ -492,10 +484,7 @@ def get_access_token_for_resource(self, resource_url: str) -> str:
492484 result = self .app .acquire_token_silent (sharepoint_scopes , account = None )
493485 if result and "access_token" in result :
494486 access_token = result ["access_token" ]
495- # Verify token (security enhancement)
496- claims = _verify_access_token_if_present (access_token )
497- if claims :
498- logger .debug ("SharePoint resource token verified, tenant=%s" , claims .get ("tid" ))
487+ _verify_access_token (access_token ) # raises JWTVerificationError on failure
499488 logger .info ("SharePoint get_access_token_for_resource: Fallback success" )
500489 return access_token
501490
0 commit comments