Forum Discussion

g3kuser's avatar
g3kuser
Helper II
1 year ago
Solved

Fabric APIs from notebook using SPN auth

Hi,

 

I need to call Fabric APIs from notebook to get workspace, items and create shortcuts but getting following error just for shortcut creation. 

'errorCode': 'InsufficientScopes', 'message': 'The caller does not have sufficient scopes to perform this operation'

 

The notebook owner is SPN as it is deployed through fabric ci-cd python library.

I tried following scopes but nothing worked for shortcut creation.

token_string = mssparkutils.credentials.getToken("pbi")

token_string = mssparkutils.credentials.getToken("https://api.fabric.microsoft.com/.default")

 

Similarly getting error while retrieving connections /v1/connections.

 

I noticed if I explicitly get token through ClientSecretCredential class and it worked fine to create shortcuts.

client_secret_credential_class = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
access_token_class = client_secret_credential_class.get_token(scope)
token_string = access_token_class.token
 
I would like to get this working without explicitly setting up credential class as it would work for any executing user either named user/SPN.
 
Any thoughts?
 

Thanks,

 

Gayatri

  • Anonymous's avatar
    Anonymous
    1 year ago

    Hi g3kuser ,

     

    As you're building a generic framework that should work for both named users and SPNs, but you're hitting limitations where:
     
    >>Direct use of ClientSecretCredential works for SPNs.
    >>mssparkutils.credentials.getToken(...) does not work for some endpoints (e.g., shortcut creation, connections) under SPN context.
     
    Cause for the issue might be,
                       The token retrieved using mssparkutils.credentials.getToken(...) does not always include all required scopes — particularly for application-level permissions used by SPNs. It's likely retrieving a user-delegated token, or a token with limited/default scopes.
     
    This mismatch causes InsufficientScopes errors on more privileged Fabric APIs like:
    *POST /v1/workspaces/{workspaceId}/shortcuts
    *GET /v1/connections
     
    These often require app-level roles and proper access tokens issued via the client credentials flow.
    We can suggest that,
    Since you want a framework-agnostic approach, here’s how you can proceed:
     
    **Differentiate Named User vs SPN Execution
    Use this logic to detect if the notebook is running under a user or an SPN:
    try:
        user = mssparkutils.env.getUserName()
        is_spn = False
    except:
        is_spn = True
     
    else, you can check the structure of the returned token or decode the JWT to see if it’s an app (SPN) or user principal.
    Split Authentication Flow Dynamically
    if is_spn:
        # Use explicit credential (ClientSecretCredential) for SPN
        credential = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
        access_token = credential.get_token(scope)
        token_string = access_token.token
    else:
        # Use mssparkutils for user context
        token_string = mssparkutils.credentials.getToken("https://api.fabric.microsoft.com/.default")
    This ensures the right token with correct scopes is used based on the execution context.
     
    If these workarounds don't help you,
    I suggest reaching out to Microsoft Support by raising a ticket. Microsoft will analyze backend logs and provide a resolution
     
    Below is the link to create Microsoft support ticket:
     
    If this post helps, then please consider Accepting as solution to help the other members find it more quickly, don't forget to give a "Kudos" – I’d truly appreciate it!

    Regards,
    B Manikanteswara Reddy

4 Replies

  • Anonymous's avatar
    Anonymous
    Not applicable

    Hi g3kuser ,

     

    Thank you for reaching out to Microsoft Fabric Community Forum.

     

    Since the notebook is being executed under a Service Principal (SPN), you'll need to ensure the app registration in Azure AD is correctly configured for the required permissions.

    --Register the SPN (app) in Azure Active Directory, and assign the necessary API permissions for Microsoft Fabric.

    --Recommended application-level permissions:

    Tenant.Read.All

    Workspace.ReadWrite.All

    Shortcut.Create.All (if available)

    --If you’re using the client credentials flow, you can also work with the /.default scope to inherit all granted permissions.

    --After adding the permissions, make sure an Azure AD Admin grants admin consent to them.

    Then, you can authenticate using the ClientSecretCredential as follows:


    scope = 'https://api.fabric.microsoft.com/.default'
    credential = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
    access_token = credential.get_token(scope)
    token_string = access_token.token

     

    This approach ensures that your Service Principal has the correct permissions to perform operations like creating shortcuts or managing connections through the Fabric APIs.


    If this post helps, then please consider Accepting as solution to help the other members find it more quickly, don't forget to give a "Kudos" – I’d truly appreciate it!

     

    Regards,

    B Manikanteswara Reddy

    • g3kuser's avatar
      g3kuser
      Helper II

      My app is granted correct permission and I can make the calls successul by explicitly initializing credential object but it fails when only for few endpoints when I don't initialize and get token through mssparkutils. 

       

      token_string = mssparkutils.credentials.getToken("pbi")

      token_string = mssparkutils.credentials.getToken("https://api.fabric.microsoft.com/.default")
       
      I don't want to initialize credential class explicilty as I am trying to develop a framework wherein if executed by named user/SPN it should generate the same results. 
       
      I also tried to identify executing user in notebook using mssparkutils.env.getUserName which returns entire email of named user but in case of SPN as executing user it fails. Atleast if I find a way to differentiate then I split the flow as needed.
       
      Thanks,
       
      Gayatri
      • Anonymous's avatar
        Anonymous
        Not applicable

        Hi g3kuser ,

         

        As you're building a generic framework that should work for both named users and SPNs, but you're hitting limitations where:
         
        >>Direct use of ClientSecretCredential works for SPNs.
        >>mssparkutils.credentials.getToken(...) does not work for some endpoints (e.g., shortcut creation, connections) under SPN context.
         
        Cause for the issue might be,
                           The token retrieved using mssparkutils.credentials.getToken(...) does not always include all required scopes — particularly for application-level permissions used by SPNs. It's likely retrieving a user-delegated token, or a token with limited/default scopes.
         
        This mismatch causes InsufficientScopes errors on more privileged Fabric APIs like:
        *POST /v1/workspaces/{workspaceId}/shortcuts
        *GET /v1/connections
         
        These often require app-level roles and proper access tokens issued via the client credentials flow.
        We can suggest that,
        Since you want a framework-agnostic approach, here’s how you can proceed:
         
        **Differentiate Named User vs SPN Execution
        Use this logic to detect if the notebook is running under a user or an SPN:
        try:
            user = mssparkutils.env.getUserName()
            is_spn = False
        except:
            is_spn = True
         
        else, you can check the structure of the returned token or decode the JWT to see if it’s an app (SPN) or user principal.
        Split Authentication Flow Dynamically
        if is_spn:
            # Use explicit credential (ClientSecretCredential) for SPN
            credential = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
            access_token = credential.get_token(scope)
            token_string = access_token.token
        else:
            # Use mssparkutils for user context
            token_string = mssparkutils.credentials.getToken("https://api.fabric.microsoft.com/.default")
        This ensures the right token with correct scopes is used based on the execution context.
         
        If these workarounds don't help you,
        I suggest reaching out to Microsoft Support by raising a ticket. Microsoft will analyze backend logs and provide a resolution
         
        Below is the link to create Microsoft support ticket:
         
        If this post helps, then please consider Accepting as solution to help the other members find it more quickly, don't forget to give a "Kudos" – I’d truly appreciate it!

        Regards,
        B Manikanteswara Reddy