Skip to content

Commit 98bcfb3

Browse files
committed
Convert most built-in samples from json to dotenv
1 parent 2d03ad9 commit 98bcfb3

7 files changed

+221
-120
lines changed

sample/.env.sample.entra-id

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This sample can be configured to work with Microsoft Entra ID.
2+
#
3+
# If you are using a Microsoft Entra ID tenant,
4+
# configure the AUTHORITY variable as
5+
# "https://login.microsoftonline.com/TENANT_GUID"
6+
# or "https://login.microsoftonline.com/contoso.onmicrosoft.com".
7+
#
8+
# Alternatively, use "https://login.microsoftonline.com/common" for multi-tenant app.
9+
AUTHORITY=<authority url>
10+
11+
# The following variables are required for the app to run.
12+
CLIENT_ID=<client id>
13+
14+
# Leave it empty if you are using a public client which has no client secret.
15+
CLIENT_SECRET=<client secret>
16+
17+
# Multiple scopes can be added into the same line, separated by a space.
18+
# Here we use a Microsoft Graph API as an example
19+
# You may need to use your own API's scope.
20+
SCOPE=<your scopes>
21+
22+
# Required if the sample app wants to call an API.
23+
#ENDPOINT=https://graph.microsoft.com/v1.0/me
24+
25+
# Required if you are testing the username_password_sample.py
26+
#USERNAME=<username>

sample/.env.sample.external-id

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This sample can be configured to work with Microsoft External ID.
2+
#
3+
# If you are using a Microsoft Entra External ID for customers (CIAM) tenant,
4+
# configure AUTHORITY as https://contoso.ciamlogin.com/contoso.onmicrosoft.com
5+
AUTHORITY=<authority url>
6+
7+
# The following variables are required for the app to run.
8+
CLIENT_ID=<client id>
9+
10+
# Leave it empty if you are using a public client which has no client secret.
11+
CLIENT_SECRET=<client secret>
12+
13+
# Multiple scopes can be added into the same line, separated by a space.
14+
# Here we use a Microsoft Graph API as an example
15+
# You may need to use your own API's scope.
16+
SCOPE=<your scopes>
17+
18+
# Required if the sample app wants to call an API.
19+
#ENDPOINT=https://graph.microsoft.com/v1.0/me
20+
21+
# Required if you are testing the username_password_sample.py
22+
#USERNAME=<username>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# This sample can be configured to work with Microsoft External ID with custom domain.
2+
#
3+
# If you are using a Microsoft External ID tenant with custom domain,
4+
# configure the OIDC_AUTHORITY variable as
5+
# "https://www.contoso.com/TENANT_GUID/v2.0"
6+
OIDC_AUTHORITY=<authority url>
7+
8+
# The following variables are required for the app to run.
9+
CLIENT_ID=<client id>
10+
11+
# Leave it empty if you are using a public client which has no client secret.
12+
CLIENT_SECRET=<client secret>
13+
14+
# Multiple scopes can be added into the same line, separated by a space.
15+
# Here we use a Microsoft Graph API as an example
16+
# You may need to use your own API's scope.
17+
SCOPE=<your scopes>
18+
19+
# Required if the sample app wants to call an API.
20+
#ENDPOINT=https://graph.microsoft.com/v1.0/me
21+
22+
# Required if you are testing the username_password_sample.py
23+
#USERNAME=<username>

sample/confidential_client_secret_sample.py

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,37 @@
11
"""
2-
The configuration file would look like this (sans those // comments):
3-
4-
{
5-
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
6-
"client_id": "your_client_id came from https://learn.microsoft.com/entra/identity-platform/quickstart-register-app",
7-
"scope": ["https://graph.microsoft.com/.default"],
8-
// Specific to Client Credentials Grant i.e. acquire_token_for_client(),
9-
// you don't specify, in the code, the individual scopes you want to access.
10-
// Instead, you statically declared them when registering your application.
11-
// Therefore the only possible scope is "resource/.default"
12-
// (here "https://graph.microsoft.com/.default")
13-
// which means "the static permissions defined in the application".
14-
15-
"secret": "The secret generated by AAD during your confidential app registration",
16-
// For information about generating client secret, refer:
17-
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#registering-client-secrets-using-the-application-registration-portal
18-
19-
"endpoint": "https://graph.microsoft.com/v1.0/users"
20-
// For this resource to work, you need to visit Application Permissions
21-
// page in portal, declare scope User.Read.All, which needs admin consent
22-
// https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/1-Call-MsGraph-WithSecret/README.md
23-
}
24-
25-
You can then run this sample with a JSON configuration file:
26-
27-
python sample.py parameters.json
2+
This sample demonstrates a daemon application that acquires a token using a
3+
client secret and then calls a web API with the token.
4+
5+
This sample loads its configuration from a .env file.
6+
7+
To make this sample work, you need to choose one of the following templates:
8+
9+
.env.sample.entra-id
10+
.env.sample.external-id
11+
.env.sample.external-id-with-custom-domain
12+
13+
Copy the chosen template to a new file named .env, and fill in the values.
14+
15+
You can then run this sample:
16+
17+
python name_of_this_script.py
2818
"""
2919

30-
import sys # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
3120
import json
3221
import logging
22+
import os
3323
import time
3424

35-
import requests
25+
from dotenv import load_dotenv # Need "pip install python-dotenv"
3626
import msal
27+
import requests
3728

3829

3930
# Optional logging
4031
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
4132
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
4233

43-
config = json.load(open(sys.argv[1]))
34+
load_dotenv() # We use this to load configuration from a .env file
4435

4536
# If for whatever reason you plan to recreate same ClientApplication periodically,
4637
# you shall create one global token cache and reuse it by each ClientApplication
@@ -49,25 +40,32 @@
4940

5041
# Create a preferably long-lived app instance, to avoid the overhead of app creation
5142
global_app = msal.ConfidentialClientApplication(
52-
config["client_id"], authority=config["authority"],
53-
client_credential=config["secret"],
43+
os.getenv('CLIENT_ID'),
44+
authority=os.getenv('AUTHORITY'), # For Entra ID or External ID
45+
oidc_authority=os.getenv('OIDC_AUTHORITY'), # For External ID with custom domain
46+
client_credential=os.getenv('CLIENT_SECRET'),
5447
token_cache=global_token_cache, # Let this app (re)use an existing token cache.
5548
# If absent, ClientApplication will create its own empty token cache
5649
)
50+
scopes = os.getenv("SCOPE", "").split()
5751

5852

5953
def acquire_and_use_token():
6054
# Since MSAL 1.23, acquire_token_for_client(...) will automatically look up
6155
# a token from cache, and fall back to acquire a fresh token when needed.
62-
result = global_app.acquire_token_for_client(scopes=config["scope"])
56+
result = global_app.acquire_token_for_client(scopes=scopes)
6357

6458
if "access_token" in result:
6559
print("Token was obtained from:", result["token_source"]) # Since MSAL 1.25
66-
# Calling graph using the access token
67-
graph_data = requests.get( # Use token to call downstream service
68-
config["endpoint"],
69-
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
70-
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
60+
if os.getenv('ENDPOINT'):
61+
# Calling a web API using the access token
62+
api_result = requests.get(
63+
os.getenv('ENDPOINT'),
64+
headers={'Authorization': 'Bearer ' + result['access_token']},
65+
).json() # Assuming the response is JSON
66+
print("Web API call result", json.dumps(api_result, indent=2))
67+
else:
68+
print("Token acquisition result", json.dumps(result, indent=2))
7169
else:
7270
print("Token acquisition failed", result) # Examine result["error_description"] etc. to diagnose error
7371

sample/device_flow_sample.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,39 @@
11
"""
2+
This sample demonstrates a headless application that acquires a token using
3+
the device code flow and then calls a web API with the token.
24
The configuration file would look like this:
35
4-
{
5-
"authority": "https://login.microsoftonline.com/common",
6-
"client_id": "your_client_id came from https://learn.microsoft.com/entra/identity-platform/quickstart-register-app",
7-
"scope": ["User.ReadBasic.All"],
8-
// You can find the other permission names from this document
9-
// https://docs.microsoft.com/en-us/graph/permissions-reference
10-
"endpoint": "https://graph.microsoft.com/v1.0/users"
11-
// You can find more Microsoft Graph API endpoints from Graph Explorer
12-
// https://developer.microsoft.com/en-us/graph/graph-explorer
13-
}
6+
This sample loads its configuration from a .env file.
147
15-
You can then run this sample with a JSON configuration file:
8+
To make this sample work, you need to choose one of the following templates:
169
17-
python sample.py parameters.json
10+
.env.sample.entra-id
11+
.env.sample.external-id
12+
.env.sample.external-id-with-custom-domain
13+
14+
Copy the chosen template to a new file named .env, and fill in the values.
15+
16+
You can then run this sample:
17+
18+
python name_of_this_script.py
1819
"""
1920

20-
import sys # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
2121
import json
2222
import logging
23+
import os
24+
import sys
2325
import time
2426

25-
import requests
27+
from dotenv import load_dotenv # Need "pip install python-dotenv"
2628
import msal
29+
import requests
2730

2831

2932
# Optional logging
3033
# logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
3134
# logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
3235

33-
config = json.load(open(sys.argv[1]))
36+
load_dotenv() # We use this to load configuration from a .env file
3437

3538
# If for whatever reason you plan to recreate same ClientApplication periodically,
3639
# you shall create one global token cache and reuse it by each ClientApplication
@@ -39,10 +42,13 @@
3942

4043
# Create a preferably long-lived app instance, to avoid the overhead of app creation
4144
global_app = msal.PublicClientApplication(
42-
config["client_id"], authority=config["authority"],
45+
os.getenv('CLIENT_ID'),
46+
authority=os.getenv('AUTHORITY'), # For Entra ID or External ID
47+
oidc_authority=os.getenv('OIDC_AUTHORITY'), # For External ID with custom domain
4348
token_cache=global_token_cache, # Let this app (re)use an existing token cache.
4449
# If absent, ClientApplication will create its own empty token cache
4550
)
51+
scopes = os.getenv("SCOPE", "").split()
4652

4753

4854
def acquire_and_use_token():
@@ -61,12 +67,12 @@ def acquire_and_use_token():
6167
# Assuming the end user chose this one
6268
chosen = accounts[0]
6369
# Now let's try to find a token in cache for this account
64-
result = global_app.acquire_token_silent(config["scope"], account=chosen)
70+
result = global_app.acquire_token_silent(scopes, account=chosen)
6571

6672
if not result:
6773
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
6874

69-
flow = global_app.initiate_device_flow(scopes=config["scope"])
75+
flow = global_app.initiate_device_flow(scopes=scopes)
7076
if "user_code" not in flow:
7177
raise ValueError(
7278
"Fail to create device flow. Err: %s" % json.dumps(flow, indent=4))
@@ -85,11 +91,15 @@ def acquire_and_use_token():
8591

8692
if "access_token" in result:
8793
print("Token was obtained from:", result["token_source"]) # Since MSAL 1.25
88-
# Calling graph using the access token
89-
graph_data = requests.get( # Use token to call downstream service
90-
config["endpoint"],
91-
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
92-
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
94+
if os.getenv('ENDPOINT'):
95+
# Calling a web API using the access token
96+
api_result = requests.get(
97+
os.getenv('ENDPOINT'),
98+
headers={'Authorization': 'Bearer ' + result['access_token']},
99+
).json() # Assuming the response is JSON
100+
print("Web API call result", json.dumps(api_result, indent=2))
101+
else:
102+
print("Token acquisition result", json.dumps(result, indent=2))
93103
else:
94104
print("Token acquisition failed", result) # Examine result["error_description"] etc. to diagnose error
95105

0 commit comments

Comments
 (0)