Skip to content

Commit

Permalink
add google colab auth
Browse files Browse the repository at this point in the history
  • Loading branch information
chuongmep committed May 6, 2024
1 parent 69fbab9 commit 0d8e65b
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 54 deletions.
109 changes: 56 additions & 53 deletions APSToolkitPython/Tutorials/01. Setup And Authentication.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -70,36 +70,7 @@
"start_time": "2024-03-02T14:08:56.989455Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: aps-toolkit in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (0.5.1)\n",
"Collecting aps-toolkit\n",
" Downloading aps_toolkit-0.5.3-py3-none-any.whl.metadata (1.9 kB)\n",
"Requirement already satisfied: requests in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from aps-toolkit) (2.31.0)\n",
"Requirement already satisfied: pandas in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from aps-toolkit) (1.5.3)\n",
"Requirement already satisfied: python-dateutil>=2.8.1 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from pandas->aps-toolkit) (2.8.2)\n",
"Requirement already satisfied: pytz>=2020.1 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from pandas->aps-toolkit) (2022.7)\n",
"Requirement already satisfied: numpy>=1.21.0 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from pandas->aps-toolkit) (1.23.5)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from requests->aps-toolkit) (2.1.1)\n",
"Requirement already satisfied: idna<4,>=2.5 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from requests->aps-toolkit) (3.4)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from requests->aps-toolkit) (1.26.13)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from requests->aps-toolkit) (2024.2.2)\n",
"Requirement already satisfied: six>=1.5 in /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages (from python-dateutil>=2.8.1->pandas->aps-toolkit) (1.16.0)\n",
"Downloading aps_toolkit-0.5.3-py3-none-any.whl (55 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m55.7/55.7 kB\u001b[0m \u001b[31m496.4 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
"\u001b[?25hInstalling collected packages: aps-toolkit\n",
" Attempting uninstall: aps-toolkit\n",
" Found existing installation: aps-toolkit 0.5.1\n",
" Uninstalling aps-toolkit-0.5.1:\n",
" Successfully uninstalled aps-toolkit-0.5.1\n",
"Successfully installed aps-toolkit-0.5.3\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"outputs": [],
"source": [
"%pip install aps-toolkit --upgrade"
]
Expand Down Expand Up @@ -375,6 +346,7 @@
"source": [
"from aps_toolkit import Auth\n",
"import os\n",
"\n",
"redirect_uri = \"http://localhost:8080/api/auth/callback\"\n",
"scopes = 'data:read viewables:read'\n",
"client_id = os.environ['APS_CLIENT_PKCE_ID']\n",
Expand Down Expand Up @@ -402,6 +374,30 @@
"# new_token.refresh_token"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Get User Information\n",
"To get the user information logged in, you need to make sure that you used the 3-legged token to get the user information."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from aps_toolkit import Auth\n",
"\n",
"redirect_uri = \"http://localhost:8080/api/auth/callback\"\n",
"scopes = 'data:read viewables:read'\n",
"token = auth.auth3leg(redirect_uri, scopes)\n",
"user_infor = auth.get_user_info()\n",
"print(\"User:\", user_infor[\"name\"])\n",
"print(\"Job Title:\", user_infor[\"job_title\"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -415,11 +411,12 @@
"metadata": {},
"outputs": [],
"source": [
"# from google.colab import userdata\n",
"# client_id = userdata.get('APS_CLIENT_ID')\n",
"# client_secret = userdata.get('APS_CLIENT_SECRET')\n",
"# auth = Auth(client_id, client_secret)\n",
"# token = auth.auth2leg()"
"from google.colab import userdata\n",
"\n",
"client_id = userdata.get('APS_CLIENT_ID')\n",
"client_secret = userdata.get('APS_CLIENT_SECRET')\n",
"auth = Auth(client_id, client_secret)\n",
"token = auth.auth2leg()"
]
},
{
Expand All @@ -430,11 +427,24 @@
]
},
{
"cell_type": "markdown",
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"## Get User Information\n",
"To get the user information logged in, you need to make sure that you used the 3-legged token to get the user information."
"from aps_toolkit import AuthGoogleColab\n",
"\n",
"auth = AuthGoogleColab()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# 2leg\n",
"token = auth.auth2leg()"
]
},
{
Expand All @@ -443,30 +453,23 @@
"metadata": {},
"outputs": [],
"source": [
"from aps_toolkit import Auth\n",
"# 3leg \n",
"redirect_uri = \"http://localhost:8080/api/auth/callback\"\n",
"scopes = 'data:read viewables:read'\n",
"token = auth.auth3leg(redirect_uri, scopes)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"User: Ho Van Chuong\n",
"Job Title: Computational Design Researcher\n"
]
}
],
"outputs": [],
"source": [
"user_infor = auth.get_user_info()\n",
"print(\"User:\",user_infor[\"name\"])\n",
"print(\"Job Title:\",user_infor[\"job_title\"])"
"# 3leg PKCE\n",
"client_id = userdata.get('APS_CLIENT_PKCE_ID')\n",
"redirect_uri = \"http://localhost:8080/api/auth/callback\"\n",
"scopes = 'data:read viewables:read'\n",
"token = auth.auth3legPkce(client_id, redirect_uri, scopes)\n"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion APSToolkitPython/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setuptools.setup(
name="aps-toolkit",
version="0.5.6",
version="0.5.8",
author="chuong mep",
author_email="[email protected]",
description="A Toolkit Autodesk Platform Services for Python",
Expand Down
109 changes: 109 additions & 0 deletions APSToolkitPython/src/aps_toolkit/AuthGoogleColab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
Copyright (C) 2024 chuongmep.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from .Auth import Auth
from typing import Optional
import requests
from .Token import Token


class AuthGoogleColab(Auth):
def __init__(self, client_id: Optional[str] = None, client_secret: Optional[str] = None):
super().__init__(client_id, client_secret)

def auth3leg(self, callback_url=None, scopes=None) -> Token:
if not scopes:
scopes = 'data:read data:write data:create data:search bucket:create bucket:read bucket:update bucket:delete code:all'
if not callback_url:
# Default callback url
callback_url = "http://localhost:8080/api/auth/callback"
auth_url = f"https://developer.api.autodesk.com/authentication/v2/authorize?response_type=code&client_id={self.client_id}&redirect_uri={callback_url}&scope={scopes}"
auth_url = auth_url.replace(" ", "%20")
print(f"Click the following link to authenticate:\n{auth_url}")
auth_code = input("Enter the authorization code: ")
# Exchange the authorization code for an access token
token_url = "https://developer.api.autodesk.com/authentication/v2/token"
payload = {
"grant_type": "authorization_code",
"code": auth_code,
"client_id": self.client_id,
"client_secret": self.client_secret,
"redirect_uri": callback_url
}
response = requests.post(token_url, data=payload)
if response.status_code != 200:
raise Exception(response.content)
response_json = response.json()

# Return the token object
return Token(
access_token=response_json['access_token'],
token_type=response_json['token_type'],
expires_in=response_json['expires_in'],
refresh_token=response_json.get('refresh_token')
)

def auth3legPkce(self, clientId=None, callback_url=None, scopes=None) -> Token:
"""
This method is used to authenticate a user using the 3-legged OAuth PKCE flow.
https://aps.autodesk.com/blog/new-application-types
Parameters:
clientId (str, optional): The client ID of the application. If not provided, it will use the client ID from the environment variables.
callback_url (str, optional): The callback URL where the user will be redirected after authentication. If not provided, it defaults to "http://localhost:8080/api/auth/callback".
scopes (str, optional): The scopes for which the application is requesting access. If not provided, it defaults to 'data:read data:write data:create data:search bucket:create bucket:read bucket:update bucket:delete code:all'.
Returns:
Token: An instance of the Token class containing the access token, token type, expiration time, and refresh token (if available).
"""

if clientId:
self.client_id = clientId
if not scopes:
scopes = 'data:read data:write data:create data:search bucket:create bucket:read bucket:update bucket:delete code:all'
if not callback_url:
# Default callback url
callback_url = "http://localhost:8080/api/auth/callback"

code_verifier = self.random_string(64)
code_challenge = self.generate_code_challenge(code_verifier)

def handle_callback(callback_url, code, client_id, code_verifier):
token_url = "https://developer.api.autodesk.com/authentication/v2/token"
payload = {
"grant_type": "authorization_code",
"code": code,
"client_id": client_id,
"code_verifier": code_verifier,
"redirect_uri": callback_url
}
resp = requests.post(token_url, data=payload)
if resp.status_code != 200:
raise Exception(resp.content)
resp_json = resp.json()
return resp_json

auth_url = f"https://developer.api.autodesk.com/authentication/v2/authorize?response_type=code&client_id={self.client_id}&redirect_uri={callback_url}&scope={scopes}&code_challenge={code_challenge}&code_challenge_method=S256"
# encode the url with spaces
auth_url = auth_url.replace(" ", "%20")
print(f"Click the following link to authenticate:\n{auth_url}")
auth_code = input("Enter the authorization code: ")
response_json = handle_callback(callback_url, auth_code, self.client_id, code_verifier)
self.access_token = response_json['access_token']
self.token_type = response_json['token_type']
self.expires_in = response_json['expires_in']
self.refresh_token = response_json.get('refresh_token')
# Return the token object using the global variables
return Token(self.access_token, self.token_type, self.expires_in, self.refresh_token)
1 change: 1 addition & 0 deletions APSToolkitPython/src/aps_toolkit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .Auth import Auth
from .AuthGoogleColab import AuthGoogleColab
from .BIM360 import BIM360
from .ProDbReaderRevit import PropDbReaderRevit
from .ProDbReaderCad import PropDbReaderCad
Expand Down
1 change: 1 addition & 0 deletions APSToolkitPython/src/test/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from aps_toolkit import PropDbReaderNavis
from aps_toolkit import DbReader
from aps_toolkit import Auth
from aps_toolkit import AuthGoogleColab
from aps_toolkit import Token
from aps_toolkit import BIM360
from aps_toolkit import Fragments
Expand Down
36 changes: 36 additions & 0 deletions APSToolkitPython/src/test/test_auth_colab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from unittest import TestCase
import os
from .context import AuthGoogleColab


class TestAuth(TestCase):
def test_auth(self):
client_id = os.environ['APS_CLIENT_ID']
client_secret = os.environ['APS_CLIENT_SECRET']
auth = AuthGoogleColab(client_id, client_secret)
token = auth.auth2leg()
self.assertNotEquals(token.access_token, "")

def test_auth2leg(self):
auth = AuthGoogleColab()
token = auth.auth2leg()
self.assertNotEquals(token.access_token, "")

def test_auth3leg(self):
auth = AuthGoogleColab()
redirect_uri = "http://localhost:8080/api/auth/callback"
# https://aps.autodesk.com/en/docs/oauth/v2/developers_guide/scopes
scopes = 'data:read viewables:read'
token = auth.auth3leg(redirect_uri, scopes)
print(token.refresh_token)
self.assertNotEquals(token.access_token, "")

def test_auth3legPkce(self):
auth = AuthGoogleColab()
redirect_uri = "http://localhost:8080/api/auth/callback"
# https://aps.autodesk.com/en/docs/oauth/v2/developers_guide/scopes
scopes = 'data:read viewables:read'
client_id = os.environ['APS_CLIENT_PKCE_ID']
token = auth.auth3legPkce(client_id, redirect_uri, scopes)
print("Refresh Token:", token.refresh_token)
self.assertNotEquals(token.access_token, "")

0 comments on commit 0d8e65b

Please sign in to comment.