Working with Python Jupyter Notebooks and MS Graph in VS Code
Published: 2021-09-28 20:59:21

Lately I find myself falling in love with Python more and more. It's simple, fast and super powerful. I know I'm late to the game but you know the saying: "better late than never" :)

Since Python is my go-to language these days, I decided to use it to automate one of the mundane and tricky parts of working with Azure AD - creating an App Registration for app authentication. Every time you need to implement authentication and authorization in your applications, be it a web app, api, desktop, mobile etc, you need to register an app, or possibly multiple apps in Azure AD. This is how you create the 1:1 relationship between your code and Azure AD and where you also configure api permissions, flows etc. This can get tricky since there are multiple steps and missing one can break things. What if there was a way to automate all that and avoid human errors?

Enter the world of MS Graph and Jupyter Notebooks. 

## Set up your environment
You'll need to install the latest [Python](https://www.python.org/downloads/). I'm using Python 3.9.x and since I'm late to the game, I'm happy to avoid the whole 2v3 debacle. Straight to Python 3! 

In VS Code, you also want to install the following extensions: 
- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
- [Jupyter](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
- [Jupyter Keymap](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter-keymap)
- [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance)

##Create the project
Crate a new directory and open it in VS Code. Here, we're going to create our Python virtual environment and install our dependencies. To create and activate a virtual environment, type the following commands:

PS - I'm working on Windows so the commands are slightly different

```
python -m venv .venv
.venv/scripts/activate.ps1
```
Next, we'll create a `requirements.txt` file and add the following dependencies/packages

```
ipykernel>=6.4.1
msgraph-core>=0.2.2
azure-identity>=1.6.1
```

Use this command to install the dependencies
```
pip install -r requirements.txt
```
If you get prompted to upgrade your `pip` to stop being pestered every time you run the pip command, now is a good time. In your terminal, type the following:
```
<path to your current directory>\.venv\scripts\python.exe -m pip install --upgrade pip
```
Finally, we can use the command palette to create a new Jupyter Notebook

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5grq0qhqai9246ftyib.gif)

## Let's write some MS Graph code
To automate the Azure AD App Registration code, we can use MS Graph - the one API to rule them all! But before we write any code, we first need to.... register an app in Azure AD. Confused? I'm sure you are but let me break it down for you. To interact with Azure AD we need to be in an authenticated context. We need a way to authenticate as a user and consent to the right permissions so that we can programmatically configure Azure AD. And for this to happen, we need an App Registration. 

I have created a multitenant app registration so if you have the right permissions, you should be able to sign in with your own organizational account and run the notebook. However, if you need to create your own App Registration, then these are the steps:

1. Open the browswer and navigate to your Azure AD Portal
2. Navigate to App Registrations
3. Create a new App Registration
4. Navigate to the Authentication tab
5. Add a new Platform
6. Select Desktop and Mobile
7. Set the Redirect Uri to Custom -> `http://localhost`
8. Save everything
9. From the Overview tab, copy the Client ID

And now we can write some code :)

In the first code segment of our Jupyter Notebook, we'll initialize our Graph client and set some variables to use later. Something that you may notice is that MS Graph now relies on the `Azure.Identity` library, which is part of the Azure SDKs, for authenticating and acquiring tokens which is super neat!

```
from azure.identity import InteractiveBrowserCredential
from msgraph.core import GraphClient
import uuid
import json

browser_credential = InteractiveBrowserCredential(client_id='7537790f-b619-4d30-a804-1c6b8b7f1523')
graph_client = GraphClient(credential=browser_credential)
scopes = ['Application.ReadWrite.All', 'User.Read']
```
On the next code segment, we'll create an API App Registration and set a custom API permission. Client apps should use this scope to call our API in the future. 

```
apiAppName='automation - Python API'
apiIdentifier = f"api://{uuid.uuid4()}"
permissionId = f"{uuid.uuid4()}";

body = {
    'displayName': apiAppName,
    'identifierUris': [
        apiIdentifier           
    ], 
    'api': {
        'acceptMappedClaims': None,
        'knownClientApplications': [],
        'requestedAccessTokenVersion': 2,
        'oauth2PermissionScopes': [
            {
                'id': permissionId,
                'adminConsentDescription':'access the api as a reader',
                'adminConsentDisplayName':'access the api as a reader',
                'isEnabled': True,
                'type': 'User',
                'userConsentDescription': 'access the api as a reader',
                'userConsentDisplayName': 'access the api as a reader',
                'value':'api.read'
            }],
        'preAuthorizedApplications':[]
    }
}

result = graph_client.post('/applications',
                data=json.dumps(body),
                headers={'Content-Type': 'application/json'}
                )
appJson = json.dumps(result.json())
application = json.loads(appJson)

response = graph_client.get('/organization')
tenantJson = json.dumps(response.json())
tenant = json.loads(tenantJson)

print(f"Client Id: {application['appId']}")
print(f"Domain: {application['publisherDomain']}")
print(f"Tenant Id: {tenant['value'][0]['id']}")
```
For your example, you'll have to change the `ApiAppName` and `ApiPermission` variable values to make them meaningful to you and you're ready to go!

## Show me teh c0dez
If you want to grab the Notebook and run it on your end, check out the [GitHub repo](https://github.com/425show/PythonInteractiveGraphSample)