Skip to content

Commit 055fa6d

Browse files
committed
Code flow authentication for persistent session. Addresses #2
- Add .gitattributes file to recognize .ipynb files as Python - Add .gitignore - resources folder is renamed to assets
1 parent 548a563 commit 055fa6d

15 files changed

+314
-49
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.ipynb linguist-language=Python
2+

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
/**/.ipynb_checkpoints
3+
/**/__pycache__
4+
/venv

Azure_app_signup_step_by_step.md

+18-23
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,48 @@
11
```python
22
# Program: Accessing OneDrive via Graph API
3-
# Author: Pranab Das (Twitter: @Pranab_Das)
4-
# Version: 20191104
3+
# Author: Pranab Das (GitHub: @pranabdas)
4+
# Version: 20191104
55
```
66

77
# Azure App Signup step by step
88

9-
1. Go to https://portal.azure.com
9+
1. Go to https://portal.azure.com
1010

11-
![01.PNG](/resources/01.PNG)
11+
![01.PNG](/assets/01.PNG)
1212

1313
2. Navigate to Azure Active Directory
1414

15-
![02.PNG](/resources/02.PNG)
15+
![02.PNG](/assets/02.PNG)
1616

1717

1818
3. Select App Registration
1919

20-
![03.PNG](/resources/03.PNG)
20+
![03.PNG](/assets/03.PNG)
2121

2222
4. Click New Registration
2323

24-
![04.PNG](/resources/04.PNG)
24+
![04.PNG](/assets/04.PNG)
2525

26-
5. Give a name to your app, set the redirect URL, and hit Registration button.
26+
5. Give a name to your app, set the redirect URL, and hit Registration button.
2727

28-
![05.PNG](/resources/05.PNG)
28+
![05.PNG](/assets/05.PNG)
2929

30-
6. Note down the client ID and go to API permissions.
30+
6. Note down the client ID and go to API permissions.
3131

32-
![06.PNG](/resources/06.PNG)
32+
![06.PNG](/assets/06.PNG)
3333

34-
7. Click Add permissions, select Microsoft Graph.
34+
7. Click Add permissions, select Microsoft Graph.
3535

36-
![07.PNG](/resources/07.PNG)
36+
![07.PNG](/assets/07.PNG)
3737

38-
8. Choose Delegated permission.
38+
8. Choose Delegated permission.
3939

40-
![08.PNG](/resources/08.PNG)
40+
![08.PNG](/assets/08.PNG)
4141

42-
9. We will add Files.ReadWrite.All for our purpose.
42+
9. We will add Files.ReadWrite.All for our purpose.
4343

44-
![09.PNG](/resources/09.PNG)
44+
![09.PNG](/assets/09.PNG)
4545

4646
10. Now go to Authentication tab, and enable Access token. Click the save button, and now we are all set to go.
4747

48-
![10.PNG](/resources/10.PNG)
49-
50-
51-
```python
52-
53-
```
48+
![10.PNG](/assets/10.PNG)

OneDrive_Gaph_tutorial.ipynb

+165-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"outputs": [],
88
"source": [
99
"# Program: Accessing OneDrive via Graph API\n",
10-
"# Author: Pranab Das (Twitter: @Pranab_Das)\n",
10+
"# Author: Pranab Das (GitHub: @pranabdas)\n",
1111
"# Version: 20210820"
1212
]
1313
},
@@ -21,14 +21,19 @@
2121
"import requests\n",
2222
"import json\n",
2323
"import urllib\n",
24-
"import os"
24+
"import os\n",
25+
"from getpass import getpass\n",
26+
"import time\n",
27+
"from datetime import datetime"
2528
]
2629
},
2730
{
2831
"cell_type": "markdown",
2932
"metadata": {},
3033
"source": [
31-
"### Get Access token"
34+
"## Get Access token\n",
35+
"\n",
36+
"### Token flow authentication"
3237
]
3338
},
3439
{
@@ -85,7 +90,154 @@
8590
"cell_type": "markdown",
8691
"metadata": {},
8792
"source": [
88-
"Looks all right. We have got the access token, and included in the HEADERS. You can print response to see more. "
93+
"Looks all right. We have got the access token, and included in the HEADERS. You can print response to see more. Go ahead with OneDrive operations."
94+
]
95+
},
96+
{
97+
"cell_type": "markdown",
98+
"metadata": {},
99+
"source": [
100+
"### Code flow authentication\n",
101+
"\n",
102+
"Code flow returns both `access_token` and `refresh_token` which can be used to\n",
103+
"request new `access_token` and `refresh_token` for persistent session. If you \n",
104+
"are using organization account, you might require consent of organization administrator. \n"
105+
]
106+
},
107+
{
108+
"cell_type": "code",
109+
"execution_count": null,
110+
"metadata": {},
111+
"outputs": [],
112+
"source": [
113+
"# Get code\n",
114+
"URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'\n",
115+
"client_id = \"362422eb-d9d6-4245-9eca-2be5cf256450\"\n",
116+
"permissions = ['offline_access', 'files.readwrite', 'User.Read']\n",
117+
"response_type = 'code'\n",
118+
"redirect_uri = 'http://localhost:8080/'\n",
119+
"scope = ''\n",
120+
"for items in range(len(permissions)):\n",
121+
" scope = scope + permissions[items]\n",
122+
" if items < len(permissions)-1:\n",
123+
" scope = scope + '+'\n",
124+
"\n",
125+
"print('Click over this link ' +URL + '?client_id=' + client_id + '&scope=' + scope + '&response_type=' + response_type+\\\n",
126+
" '&redirect_uri=' + urllib.parse.quote(redirect_uri))\n",
127+
"print('Sign in to your account, copy the whole redirected URL.')\n",
128+
"code = getpass(\"Paste the URL here :\")\n",
129+
"code = code[(code.find('?code') + len('?code') + 1) :]\n",
130+
"\n",
131+
"URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'\n",
132+
"\n",
133+
"response = requests.post(URL + '?client_id=' + client_id + '&scope=' + scope + '&grant_type=authorization_code' +\\\n",
134+
" '&redirect_uri=' + urllib.parse.quote(redirect_uri)+ '&code=' + code)"
135+
]
136+
},
137+
{
138+
"cell_type": "code",
139+
"execution_count": null,
140+
"metadata": {},
141+
"outputs": [],
142+
"source": [
143+
"# Get token\n",
144+
"data = {\n",
145+
" \"client_id\": client_id,\n",
146+
" \"scope\": permissions,\n",
147+
" \"code\": code,\n",
148+
" \"redirect_uri\": redirect_uri,\n",
149+
" \"grant_type\": 'authorization_code',\n",
150+
" \"client_secret\": client_secret\n",
151+
"}\n",
152+
"\n",
153+
"response = requests.post(URL, data=data)\n",
154+
"\n",
155+
"token = json.loads(response.text)[\"access_token\"]\n",
156+
"refresh_token = json.loads(response.text)[\"refresh_token\"]"
157+
]
158+
},
159+
{
160+
"cell_type": "code",
161+
"execution_count": null,
162+
"metadata": {},
163+
"outputs": [],
164+
"source": [
165+
"# Refresh token\n",
166+
"def get_refresh_token():\n",
167+
" data = {\n",
168+
" \"client_id\": client_id,\n",
169+
" \"scope\": permissions,\n",
170+
" \"refresh_token\": refresh_token,\n",
171+
" \"redirect_uri\": redirect_uri,\n",
172+
" \"grant_type\": 'refresh_token',\n",
173+
" \"client_secret\": 'xxxx-yyyy-zzzz',\n",
174+
" }\n",
175+
"\n",
176+
" response = requests.post(URL, data=data)\n",
177+
"\n",
178+
" token = json.loads(response.text)[\"access_token\"]\n",
179+
" refresh_token = json.loads(response.text)[\"refresh_token\"]\n",
180+
" last_updated = time.mktime(datetime.today().timetuple())\n",
181+
"\n",
182+
" return token, refresh_token, last_updated"
183+
]
184+
},
185+
{
186+
"cell_type": "code",
187+
"execution_count": null,
188+
"metadata": {},
189+
"outputs": [],
190+
"source": [
191+
"token, refresh_token, last_updated = get_refresh_token()"
192+
]
193+
},
194+
{
195+
"cell_type": "markdown",
196+
"metadata": {},
197+
"source": [
198+
"If you have a large data to upload, you may use below mock code inside your upload loop:\n",
199+
"\n",
200+
"```python\n",
201+
"elapsed_time = time.mktime(datetime.today().timetuple()) - last_updated\n",
202+
"\n",
203+
"if (elapsed_time < 45*60*60):\n",
204+
" do_something()\n",
205+
"else if (elapsed_time < 59*60*60):\n",
206+
" token, refresh_token, last_updated = get_refresh_token()\n",
207+
"else:\n",
208+
" go_to_code_flow()\n",
209+
"```"
210+
]
211+
},
212+
{
213+
"cell_type": "markdown",
214+
"metadata": {},
215+
"source": [
216+
"## OneDrive operations"
217+
]
218+
},
219+
{
220+
"cell_type": "code",
221+
"execution_count": null,
222+
"metadata": {},
223+
"outputs": [],
224+
"source": [
225+
"URL = 'https://graph.microsoft.com/v1.0/'\n",
226+
"\n",
227+
"HEADERS = {'Authorization': 'Bearer ' + token}\n",
228+
"\n",
229+
"response = requests.get(URL + 'me/drive/', headers = HEADERS)\n",
230+
"if (response.status_code == 200):\n",
231+
" response = json.loads(response.text)\n",
232+
" print('Connected to the OneDrive of', response['owner']['user']['displayName']+' (',response['driveType']+' ).', \\\n",
233+
" '\\nConnection valid for one hour. Refresh token if required.')\n",
234+
"elif (response.status_code == 401):\n",
235+
" response = json.loads(response.text)\n",
236+
" print('API Error! : ', response['error']['code'],\\\n",
237+
" '\\nSee response for more details.')\n",
238+
"else:\n",
239+
" response = json.loads(response.text)\n",
240+
" print('Unknown error! See response for more details.')"
89241
]
90242
},
91243
{
@@ -251,13 +403,17 @@
251403
]
252404
},
253405
{
406+
"cell_type": "markdown",
407+
"metadata": {},
254408
"source": [
255409
"### Move itme"
256-
],
257-
"cell_type": "markdown",
258-
"metadata": {}
410+
]
259411
},
260412
{
413+
"cell_type": "code",
414+
"execution_count": null,
415+
"metadata": {},
416+
"outputs": [],
261417
"source": [
262418
"# url = URL + 'me/drive/items/{item-id-of-item-to-be-moved}'\n",
263419
"# provide item-id-of-destination-directory under parentReference in the body\n",
@@ -268,11 +424,7 @@
268424
" },\n",
269425
"}\n",
270426
"response = json.loads(requests.patch(url, headers=HEADERS, json=body).text)"
271-
],
272-
"cell_type": "code",
273-
"metadata": {},
274-
"execution_count": null,
275-
"outputs": []
427+
]
276428
},
277429
{
278430
"cell_type": "markdown",
@@ -577,4 +729,4 @@
577729
},
578730
"nbformat": 4,
579731
"nbformat_minor": 2
580-
}
732+
}

0 commit comments

Comments
 (0)