# Using Service Principal Authentication With FabricRestClient

I wrote a [blog on using FabricRestClient](https://fabric.guru/using-fabricrestclient-to-make-fabric-rest-api-calls) from Semantic Link to call Power/Fabric REST API in Fabric notebooks. It makes it super easy. However, as I noted in the blog, it uses the calling user’s identify. It didn’t support SPN. Well, that was then and now you can use SPN to generate auth token.

All I had to do was see how [Semantic Link Lab](https://github.com/microsoft/semantic-link-labs/tree/main/src/sempy_labs) does it. I looked at the source code (Labs is open source) and copy it. So, all credit goes to Michael Kovalsky and Semantic Link Labs contributors, I am just copying what they did.

* Create a service principal. Make sure you give it the permissions as required by whichever API you are calling and the API supports SPN (check the API documentation for that)
    
* Create client secret
    
* While optional, I very highly recommend using Azure Key Vault (hopefully one day this will be possible natively in Fabric) to store the SPN credentials. Use `notebookutils` to retrieve the creds from AKV.
    

Below, I create a class to get the token which is used in `FabricRestClient` .

```python
from sempy.fabric import FabricRestClient
from azure.identity import ClientSecretCredential

key_vault = "https://sempykeyvaultsandeep.vault.azure.net/"
tenant_id = notebookutils.credentials.getSecret(key_vault , "tenantid") 
client_id = notebookutils.credentials.getSecret(key_vault , "clientid") 
client_secret = notebookutils.credentials.getSecret(key_vault , "secret") 

class ServicePrincipalTokenProvider:
    def __init__(self, tenant_id, client_id, client_secret):
        self.credential = ClientSecretCredential(
            tenant_id=tenant_id,
            client_id=client_id,
            client_secret=client_secret
        )
        # The scope for the API
        self.scope = "https://analysis.windows.net/powerbi/api/.default"
    
    def __call__(self):
        token = self.credential.get_token(self.scope)
        return token.token

# init service principal credentials
token_provider = ServicePrincipalTokenProvider(
    tenant_id=tenant_id,
    client_id=client_id,
    client_secret=client_secret
)

# Create the Fabric client
client = FabricRestClient(token_provider=token_provider)

# call the required API, below is using admin api to get tennat settings
# change the api url as required
response = client.get("/v1/admin/tenantsettings")
response.json()
```

If you have used the `.admin` functions in Labs, you know that it uses the context managers to call the API, i.e. you use `with` to localize the call. You don’t have to but that’s the recommended way to ensure isolation, security and performance. With the context manager, you use the SPN token only during that particular call and use your own identify for all other calls. Let’s implement that too:

```python
from sempy.fabric import FabricRestClient
from azure.identity import ClientSecretCredential
import contextlib

class ServicePrincipalAuth: #base class
    def __init__(self, tenant_id, client_id, client_secret):
        self.tenant_id = tenant_id
        self.client_id = client_id
        self.client_secret = client_secret
        self.client = None
        
    def __enter__(self):
        token_provider = self._create_token_provider()
        self.client = FabricRestClient(token_provider=token_provider)
        return self.client
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        
        self.client = None
        
    def _create_token_provider(self):
        # create a creds
        credential = ClientSecretCredential(
            tenant_id=self.tenant_id,
            client_id=self.client_id,
            client_secret=self.client_secret
        )
        
        def token_provider(): #replace the provder url if required
            token = credential.get_token("https://analysis.windows.net/powerbi/api/.default")
            return token.token
            
        return token_provider

# use it in context manager
with ServicePrincipalAuth(tenant_id, client_id, client_secret) as client:
    # Use the client inside the context - replace with the api url
    #always check the api documentation for requirements and details
    response = client.get("/v1/admin/workspaces") #get all workspaces as an admin
    # Process the response
    workspacess = response.json()
```

What are the use cases here? Well, when you call APIs directly or indirectly using Semantic Link and Semantic Link Labs, you use your own identify. But with SPN you can execute notebooks using your identify but call APIs using the SPN as required.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I would highly encourage using the functions available in Semantic Link and Semantic Link Lab wherever possible because those are optimized, handle LRO requests, pagination etc. Above is a very basic implementation. Look at SLL’s source code for details.</div>
</div>

Thanks again to Semantic Link Labs !

## Resources

* Refer to this if you want to learn more about SPNs: [https://youtu.be/1SO19uik1rw?si=hUemf6qJbRuShaz1](https://youtu.be/1SO19uik1rw?si=hUemf6qJbRuShaz1)
    
* Another guide for setting up SPN: [Fivetran for OneLake | Destination Setup Guide](https://fivetran.com/docs/destinations/onelake/setup-guide)
    
* [What is semantic link? - Microsoft Fabric | Microsoft Learn](https://learn.microsoft.com/en-us/fabric/data-science/semantic-link-overview)
    
* [microsoft/semantic-link-labs: Early access to new features for Microsoft Fabric's Semantic Link.](https://github.com/microsoft/semantic-link-labs)
    
* [About | Elegant BI](https://www.elegantbi.com/about)
    
* [Scan Fabric Workspaces With Scanner API Using Semantic Link Labs](https://fabric.guru/scan-fabric-workspaces-with-scanner-api-using-semantic-link-labs)
    
* [Using FabricRestClient To Make Fabric REST API Calls](https://fabric.guru/using-fabricrestclient-to-make-fabric-rest-api-calls)
    
* [Microsoft Fabric REST API references - Microsoft Fabric REST APIs | Microsoft Learn](https://learn.microsoft.com/en-us/rest/api/fabric/articles/)
