Module autodesk_forge_sdk.auth
Clients for working with the Forge Authentication service.
Expand source code
"""
Clients for working with the Forge Authentication service.
"""
from enum import Enum
from datetime import datetime, timedelta
from urllib.parse import quote
from .base import BaseClient
BASE_URL = "https://developer.api.autodesk.com/authentication/v1"
class Scope(Enum):
"""
Authentication scopes.
"""
USER_PROFILE_READ = "user-profile:read"
"""
The application will be able to read the end user’s profile data
(not including associated products and services).
"""
USER_READ = "user:read"
"""
The application will be able to read the end user’s profile data,
including associated products and services.
"""
USER_WRITE = "user:write"
"""
The application will be able to create, update, and delete the end user’s profile data,
including associated products and services.
"""
VIEWABLES_READ = "viewables:read"
"""
The application will only be able to read the end user’s viewable data
(e.g., PNG and SVF files) within the Autodesk ecosystem.
"""
DATA_READ = "data:read"
"""
The application will be able to read all the end user’s data (viewable and non-viewable)
within the Autodesk ecosystem.
"""
DATA_WRITE = "data:write"
"""
The application will be able to create, update,
and delete data on behalf of the end user within the Autodesk ecosystem.
"""
DATA_CREATE = "data:create"
"""
The application will be able to create data on behalf of the end user
within the Autodesk ecosystem.
"""
DATA_SEARCH = "data:search"
"""
The application will be able to search the end user’s data
within the Autodesk ecosystem.
"""
BUCKET_CREATE = "bucket:create"
"""The application will be able to create an OSS bucket it will own."""
BUCKET_READ = "bucket:read"
"""
The application will be able to read the metadata and list contents
for OSS buckets that it has access to.
"""
BUCKET_UPDATE = "bucket:update"
"""
The application will be able to set permissions and entitlements
for OSS buckets that it has permission to modify.
"""
BUCKET_DELETE = "bucket:delete"
"""The application will be able to delete a bucket that it has permission to delete."""
CODE_ALL = "code:all"
"""
The application will be able to author and execute code on behalf of the end user
(e.g., scripts processed by the Design Automation API).
"""
ACCOUNT_READ = "account:read"
"""
For Product APIs, the application will be able to read the account data
the end user has entitlements to.
"""
ACCOUNT_WRITE = "account:write"
"""
For Product APIs, the application will be able to update the account data
the end user has entitlements to.
"""
def get_authorization_url(
client_id: str, response_type: str, redirect_uri: str,
scopes: list[Scope], state: str = None
) -> str:
"""
Generate a URL to redirect an end user to in order to acquire the user’s consent
for your app to access the specified resources.
**Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authorize-GET
Args:
client_id (str): Client ID of the app.
response_type (str): Must be either "code" for authorization code grant flow or "token"
for implicit grant flow.
redirect_uri (str): URL-encoded callback URL that the end user will be redirected to
after completing the authorization flow.
scopes (list[Scope]): List of required scopes.
state (str, optional): Payload containing arbitrary data that the authentication flow
will pass back verbatim in a state query parameter to the callback URL.
Returns:
str: Complete authorization URL.
Examples:
```
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
client = AuthenticationClient()
url = client.get_authorization_url(
FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ])
print(url)
```
"""
url = 'https://developer.api.autodesk.com/authentication/v1/authorize'
url = url + '?client_id={}'.format(quote(client_id))
url = url + '&response_type={}'.format(response_type)
url = url + '&redirect_uri={}'.format(quote(redirect_uri))
url = url + \
'&scope={}'.format(quote(' '.join(map(lambda s: s.value, scopes))))
if state:
url += '&state={}'.format(quote(state))
return url
class AuthenticationClient(BaseClient):
"""
Forge Authentication service client.
**Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http
"""
def __init__(self, base_url: str = BASE_URL):
"""
Create new instance of the client.
Args:
base_url (str, optional): Base URL for API calls.
"""
BaseClient.__init__(self, base_url)
def authenticate(self, client_id: str, client_secret: str, scopes: list[Scope]) -> dict:
"""
Generate a two-legged access token for specific set of scopes.
**Documentation**:
https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authenticate-POST
Args:
client_id (str): Client ID of the app.
client_secret (str): Client secret of the app.
scopes (list[Scope]): List of required scopes.
Returns:
dict: Parsed response object with properties `access_token`, `token_type`,
and `expires_in`.
Examples:
```
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"]
client = AuthenticationClient()
auth = client.authenticate(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, [Scope.VIEWABLES_READ])
print(auth["access_token"])
```
"""
form = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'client_credentials',
'scope': ' '.join(map(lambda s: s.value, scopes))
}
return self._post('/authenticate', form=form).json()
def get_token(self, client_id: str, client_secret: str, code: str, redirect_uri: str) -> dict:
"""
Exchange an authorization code extracted from `get_authorization_url` callback
for a three-legged access token. This API will only be used when the 'Authorization Code'
grant type is being adopted.
**Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/gettoken-POST
Args:
client_id (str): Client ID of the app.
client_secret (str): Client secret of the app.
code (str): The authorization code captured from the code query parameter
when the user is redirected back to the callback URL.
redirect_uri (str): Must match the redirect_uri parameter
used in the `get_authorization_url`.
Returns:
dict: Parsed response object with properties `token_type`, `access_token`,
`refresh_token`, and `expires_in`.
Examples:
```
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"]
client = AuthenticationClient()
url = client.get_authorization_url(
FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ])
# redirect the user to URL, and wait for callback to http://localhost:3000/callback
code = '...' # extract 'code' query parameter from the callback
auth = client.get_token(
FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, code, "http://localhost:3000/callback")
print(auth["access_token"])
```
"""
form = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri
}
return self._post('/gettoken', form=form).json()
def refresh_token(
self, client_id: str, client_secret: str, refresh_token: str, scopes: list[Scope]) -> dict:
"""
Acquire a new access token by using the refresh token provided by `get_token`.
**Documentation**:
https://forge.autodesk.com/en/docs/oauth/v2/reference/http/refreshtoken-POST
Args:
client_id (str): Client ID of the app.
client_secret (str): Client secret of the app.
refresh_token (str): Refresh token used to acquire a new access token.
scopes (list[str]): List of required scopes.
Returns:
dict: Parsed response object with properties `token_type`, `access_token`,
`refresh_token`, and `expires_in`.
Examples:
```
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"]
refresh_token = '...' # retrieve the refresh token, for example, from cookies
client = AuthenticationClient()
auth = client.refresh_token(
FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, refresh_token, [Scope.VIEWABLES_READ])
print(auth["access_token"])
```
"""
form = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'scope': ' '.join(map(lambda s: s.value, scopes))
}
return self._post('/refreshtoken', form=form).json()
def get_user_profile(self, access_token: str) -> dict:
"""
Get the profile information of an authorizing end user in a three-legged context.
**Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/users-@me-GET
Args:
access_token (str): Token obtained via a three-legged OAuth flow.
Returns:
dict: Parsed response object with properties `userId`, `userName`, `emaillId`,
`firstName`, `lastName`, etc.
Examples:
```
access_token = '...' # get a three-legged access token, for example, from cookies
client = AuthenticationClient()
info = client.get_user_profile(access_token)
print(auth["userName"])
```
"""
headers = {'Authorization': 'Bearer {}'.format(access_token)}
return self._get('/users/@me', headers=headers).json()
class TokenProviderInterface:
"""
Interface for any class that can provide access tokens to API clients
based on a set of OAuth scopes.
"""
def get_token(self, scopes: list[Scope]) -> str:
"""
Generates access token for given set of scopes.
Args:
scopes (list[Scope]): List of scopes that the generated access token should support.
Returns:
str: Access token.
"""
raise NotImplementedError()
class SimpleTokenProvider(TokenProviderInterface):
"""
Simple implementation of `TokenProviderInterface` when you already have an access token
that you want to use. When using this approach, make sure that the hard-coded access token
supports all the scopes that may be needed.
"""
def __init__(self, access_token: str):
"""
Create new instance of the provider.
Args:
access_token (str): Token that will always be returned by
`SimpleTokenProvider.get_token`.
"""
self.access_token = access_token
def get_token(self, scopes: list[Scope]) -> str:
return self.access_token
class OAuthTokenProvider(TokenProviderInterface):
"""
Helper class that automatically generates (and caches) access tokens
using specific app credentials.
"""
def __init__(self, client_id: str, client_secret: str):
"""
Create new instance of the provider.
Args:
client_id (str): Application client ID.
client_secret (str): Application client secret.
"""
self.client_id = client_id
self.client_secret = client_secret
self.auth_client = AuthenticationClient()
self.cache = {}
def get_token(self, scopes: list[Scope]) -> str:
cache_key = "+".join(map(lambda s: s.value, scopes))
now = datetime.now()
if cache_key in self.cache:
auth = self.cache[cache_key]
if auth["expires_at"] > now:
return auth
auth = self.auth_client.authenticate(
self.client_id, self.client_secret, scopes)
auth["expires_at"] = now + timedelta(0, auth["expires_in"])
return auth
class BaseOAuthClient(BaseClient):
"""
Base class for API clients with authentication based on OAuth 2.0.
"""
def __init__(self, token_provider: TokenProviderInterface, base_url: str):
"""
Create new instance of the client.
Args:
token_provider (TokenProviderInterface): Provider that will be used
to generate access tokens for API calls.
base_url (str): Base URL for API calls.
"""
BaseClient.__init__(self, base_url)
self.token_provider = token_provider
def _head(self, url: str, **kwargs):
if "scopes" in kwargs:
if "headers" not in kwargs:
kwargs["headers"] = {}
self._set_auth_headers(kwargs["headers"], kwargs["scopes"])
del kwargs["scopes"]
return BaseClient._head(self, url, **kwargs)
def _get(self, url: str, **kwargs):
if "scopes" in kwargs:
if "headers" not in kwargs:
kwargs["headers"] = {}
self._set_auth_headers(kwargs["headers"], kwargs["scopes"])
del kwargs["scopes"]
return BaseClient._get(self, url, **kwargs)
def _post(self, url: str, form: dict = None, json: dict = None, buff=None, **kwargs):
if "scopes" in kwargs:
if "headers" not in kwargs:
kwargs["headers"] = {}
self._set_auth_headers(kwargs["headers"], kwargs["scopes"])
del kwargs["scopes"]
return BaseClient._post(self, url, form, json, buff, **kwargs)
def _put(self, url: str, form: dict = None, json: dict = None, buff=None, **kwargs):
if "scopes" in kwargs:
if "headers" not in kwargs:
kwargs["headers"] = {}
self._set_auth_headers(kwargs["headers"], kwargs["scopes"])
del kwargs["scopes"]
return BaseClient._put(self, url, form, json, buff, **kwargs)
def _delete(self, url: str, **kwargs):
if "scopes" in kwargs:
if "headers" not in kwargs:
kwargs["headers"] = {}
self._set_auth_headers(kwargs["headers"], kwargs["scopes"])
del kwargs["scopes"]
return BaseClient._delete(self, url, **kwargs)
def _set_auth_headers(self, headers: dict, scopes: list[Scope]):
if "Authorization" not in headers:
auth = self.token_provider.get_token(scopes)
headers["Authorization"] = "Bearer {}".format(auth["access_token"])
Functions
-
Generate a URL to redirect an end user to in order to acquire the user’s consent for your app to access the specified resources.
Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authorize-GET
Args
client_id
:str
- Client ID of the app.
response_type
:str
- Must be either "code" for authorization code grant flow or "token" for implicit grant flow.
redirect_uri
:str
- URL-encoded callback URL that the end user will be redirected to after completing the authorization flow.
scopes
:list[Scope]
- List of required scopes.
state
:str
, optional- Payload containing arbitrary data that the authentication flow will pass back verbatim in a state query parameter to the callback URL.
Returns
str
- Complete authorization URL.
Examples
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] client = AuthenticationClient() url = client.get_authorization_url( FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ]) print(url)
Expand source code
def get_authorization_url( client_id: str, response_type: str, redirect_uri: str, scopes: list[Scope], state: str = None ) -> str: """ Generate a URL to redirect an end user to in order to acquire the user’s consent for your app to access the specified resources. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authorize-GET Args: client_id (str): Client ID of the app. response_type (str): Must be either "code" for authorization code grant flow or "token" for implicit grant flow. redirect_uri (str): URL-encoded callback URL that the end user will be redirected to after completing the authorization flow. scopes (list[Scope]): List of required scopes. state (str, optional): Payload containing arbitrary data that the authentication flow will pass back verbatim in a state query parameter to the callback URL. Returns: str: Complete authorization URL. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] client = AuthenticationClient() url = client.get_authorization_url( FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ]) print(url) ``` """ url = 'https://developer.api.autodesk.com/authentication/v1/authorize' url = url + '?client_id={}'.format(quote(client_id)) url = url + '&response_type={}'.format(response_type) url = url + '&redirect_uri={}'.format(quote(redirect_uri)) url = url + \ '&scope={}'.format(quote(' '.join(map(lambda s: s.value, scopes)))) if state: url += '&state={}'.format(quote(state)) return url
Classes
class AuthenticationClient (base_url: str = 'https://developer.api.autodesk.com/authentication/v1')
-
Forge Authentication service client.
Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http
Create new instance of the client.
Args
base_url
:str
, optional- Base URL for API calls.
Expand source code
class AuthenticationClient(BaseClient): """ Forge Authentication service client. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http """ def __init__(self, base_url: str = BASE_URL): """ Create new instance of the client. Args: base_url (str, optional): Base URL for API calls. """ BaseClient.__init__(self, base_url) def authenticate(self, client_id: str, client_secret: str, scopes: list[Scope]) -> dict: """ Generate a two-legged access token for specific set of scopes. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authenticate-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. scopes (list[Scope]): List of required scopes. Returns: dict: Parsed response object with properties `access_token`, `token_type`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() auth = client.authenticate(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, [Scope.VIEWABLES_READ]) print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'client_credentials', 'scope': ' '.join(map(lambda s: s.value, scopes)) } return self._post('/authenticate', form=form).json() def get_token(self, client_id: str, client_secret: str, code: str, redirect_uri: str) -> dict: """ Exchange an authorization code extracted from `get_authorization_url` callback for a three-legged access token. This API will only be used when the 'Authorization Code' grant type is being adopted. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/gettoken-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. code (str): The authorization code captured from the code query parameter when the user is redirected back to the callback URL. redirect_uri (str): Must match the redirect_uri parameter used in the `get_authorization_url`. Returns: dict: Parsed response object with properties `token_type`, `access_token`, `refresh_token`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() url = client.get_authorization_url( FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ]) # redirect the user to URL, and wait for callback to http://localhost:3000/callback code = '...' # extract 'code' query parameter from the callback auth = client.get_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, code, "http://localhost:3000/callback") print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri } return self._post('/gettoken', form=form).json() def refresh_token( self, client_id: str, client_secret: str, refresh_token: str, scopes: list[Scope]) -> dict: """ Acquire a new access token by using the refresh token provided by `get_token`. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/refreshtoken-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. refresh_token (str): Refresh token used to acquire a new access token. scopes (list[str]): List of required scopes. Returns: dict: Parsed response object with properties `token_type`, `access_token`, `refresh_token`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] refresh_token = '...' # retrieve the refresh token, for example, from cookies client = AuthenticationClient() auth = client.refresh_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, refresh_token, [Scope.VIEWABLES_READ]) print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'refresh_token', 'refresh_token': refresh_token, 'scope': ' '.join(map(lambda s: s.value, scopes)) } return self._post('/refreshtoken', form=form).json() def get_user_profile(self, access_token: str) -> dict: """ Get the profile information of an authorizing end user in a three-legged context. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/users-@me-GET Args: access_token (str): Token obtained via a three-legged OAuth flow. Returns: dict: Parsed response object with properties `userId`, `userName`, `emaillId`, `firstName`, `lastName`, etc. Examples: ``` access_token = '...' # get a three-legged access token, for example, from cookies client = AuthenticationClient() info = client.get_user_profile(access_token) print(auth["userName"]) ``` """ headers = {'Authorization': 'Bearer {}'.format(access_token)} return self._get('/users/@me', headers=headers).json()
Ancestors
Methods
def authenticate(self, client_id: str, client_secret: str, scopes: list) ‑> dict
-
Generate a two-legged access token for specific set of scopes.
Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authenticate-POST
Args
client_id
:str
- Client ID of the app.
client_secret
:str
- Client secret of the app.
scopes
:list[Scope]
- List of required scopes.
Returns
dict
- Parsed response object with properties
access_token
,token_type
,
and
expires_in
.Examples
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() auth = client.authenticate(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, [Scope.VIEWABLES_READ]) print(auth["access_token"])
Expand source code
def authenticate(self, client_id: str, client_secret: str, scopes: list[Scope]) -> dict: """ Generate a two-legged access token for specific set of scopes. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/authenticate-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. scopes (list[Scope]): List of required scopes. Returns: dict: Parsed response object with properties `access_token`, `token_type`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() auth = client.authenticate(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, [Scope.VIEWABLES_READ]) print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'client_credentials', 'scope': ' '.join(map(lambda s: s.value, scopes)) } return self._post('/authenticate', form=form).json()
def get_token(self, client_id: str, client_secret: str, code: str, redirect_uri: str) ‑> dict
-
Exchange an authorization code extracted from
get_authorization_url()
callback for a three-legged access token. This API will only be used when the 'Authorization Code' grant type is being adopted.Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/gettoken-POST
Args
client_id
:str
- Client ID of the app.
client_secret
:str
- Client secret of the app.
code
:str
- The authorization code captured from the code query parameter when the user is redirected back to the callback URL.
redirect_uri
:str
- Must match the redirect_uri parameter
used in the
get_authorization_url()
.
Returns
dict
- Parsed response object with properties
token_type
,access_token
,refresh_token
, andexpires_in
.
Examples
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() url = client.get_authorization_url( FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ]) # redirect the user to URL, and wait for callback to <http://localhost:3000/callback> code = '...' # extract 'code' query parameter from the callback auth = client.get_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, code, "http://localhost:3000/callback") print(auth["access_token"])
Expand source code
def get_token(self, client_id: str, client_secret: str, code: str, redirect_uri: str) -> dict: """ Exchange an authorization code extracted from `get_authorization_url` callback for a three-legged access token. This API will only be used when the 'Authorization Code' grant type is being adopted. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/gettoken-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. code (str): The authorization code captured from the code query parameter when the user is redirected back to the callback URL. redirect_uri (str): Must match the redirect_uri parameter used in the `get_authorization_url`. Returns: dict: Parsed response object with properties `token_type`, `access_token`, `refresh_token`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] client = AuthenticationClient() url = client.get_authorization_url( FORGE_CLIENT_ID, "code", "http://localhost:3000/callback", [Scope.VIEWABLES_READ]) # redirect the user to URL, and wait for callback to http://localhost:3000/callback code = '...' # extract 'code' query parameter from the callback auth = client.get_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, code, "http://localhost:3000/callback") print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri } return self._post('/gettoken', form=form).json()
def get_user_profile(self, access_token: str) ‑> dict
-
Get the profile information of an authorizing end user in a three-legged context.
Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/users-@me-GET
Args
access_token
:str
- Token obtained via a three-legged OAuth flow.
Returns
dict
- Parsed response object with properties
userId
,userName
,emaillId
,firstName
,lastName
, etc.
Examples
access_token = '...' # get a three-legged access token, for example, from cookies client = AuthenticationClient() info = client.get_user_profile(access_token) print(auth["userName"])
Expand source code
def get_user_profile(self, access_token: str) -> dict: """ Get the profile information of an authorizing end user in a three-legged context. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/users-@me-GET Args: access_token (str): Token obtained via a three-legged OAuth flow. Returns: dict: Parsed response object with properties `userId`, `userName`, `emaillId`, `firstName`, `lastName`, etc. Examples: ``` access_token = '...' # get a three-legged access token, for example, from cookies client = AuthenticationClient() info = client.get_user_profile(access_token) print(auth["userName"]) ``` """ headers = {'Authorization': 'Bearer {}'.format(access_token)} return self._get('/users/@me', headers=headers).json()
def refresh_token(self, client_id: str, client_secret: str, refresh_token: str, scopes: list) ‑> dict
-
Acquire a new access token by using the refresh token provided by
get_token
.Documentation: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/refreshtoken-POST
Args
client_id
:str
- Client ID of the app.
client_secret
:str
- Client secret of the app.
refresh_token
:str
- Refresh token used to acquire a new access token.
scopes
:list[str]
- List of required scopes.
Returns
dict
- Parsed response object with properties
token_type
,access_token
,refresh_token
, andexpires_in
.
Examples
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] refresh_token = '...' # retrieve the refresh token, for example, from cookies client = AuthenticationClient() auth = client.refresh_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, refresh_token, [Scope.VIEWABLES_READ]) print(auth["access_token"])
Expand source code
def refresh_token( self, client_id: str, client_secret: str, refresh_token: str, scopes: list[Scope]) -> dict: """ Acquire a new access token by using the refresh token provided by `get_token`. **Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/refreshtoken-POST Args: client_id (str): Client ID of the app. client_secret (str): Client secret of the app. refresh_token (str): Refresh token used to acquire a new access token. scopes (list[str]): List of required scopes. Returns: dict: Parsed response object with properties `token_type`, `access_token`, `refresh_token`, and `expires_in`. Examples: ``` FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"] FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"] refresh_token = '...' # retrieve the refresh token, for example, from cookies client = AuthenticationClient() auth = client.refresh_token( FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, refresh_token, [Scope.VIEWABLES_READ]) print(auth["access_token"]) ``` """ form = { 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'refresh_token', 'refresh_token': refresh_token, 'scope': ' '.join(map(lambda s: s.value, scopes)) } return self._post('/refreshtoken', form=form).json()
class BaseOAuthClient (token_provider: TokenProviderInterface, base_url: str)
-
Base class for API clients with authentication based on OAuth 2.0.
Create new instance of the client.
Args
token_provider
:TokenProviderInterface
- Provider that will be used to generate access tokens for API calls.
base_url
:str
- Base URL for API calls.
Expand source code
class BaseOAuthClient(BaseClient): """ Base class for API clients with authentication based on OAuth 2.0. """ def __init__(self, token_provider: TokenProviderInterface, base_url: str): """ Create new instance of the client. Args: token_provider (TokenProviderInterface): Provider that will be used to generate access tokens for API calls. base_url (str): Base URL for API calls. """ BaseClient.__init__(self, base_url) self.token_provider = token_provider def _head(self, url: str, **kwargs): if "scopes" in kwargs: if "headers" not in kwargs: kwargs["headers"] = {} self._set_auth_headers(kwargs["headers"], kwargs["scopes"]) del kwargs["scopes"] return BaseClient._head(self, url, **kwargs) def _get(self, url: str, **kwargs): if "scopes" in kwargs: if "headers" not in kwargs: kwargs["headers"] = {} self._set_auth_headers(kwargs["headers"], kwargs["scopes"]) del kwargs["scopes"] return BaseClient._get(self, url, **kwargs) def _post(self, url: str, form: dict = None, json: dict = None, buff=None, **kwargs): if "scopes" in kwargs: if "headers" not in kwargs: kwargs["headers"] = {} self._set_auth_headers(kwargs["headers"], kwargs["scopes"]) del kwargs["scopes"] return BaseClient._post(self, url, form, json, buff, **kwargs) def _put(self, url: str, form: dict = None, json: dict = None, buff=None, **kwargs): if "scopes" in kwargs: if "headers" not in kwargs: kwargs["headers"] = {} self._set_auth_headers(kwargs["headers"], kwargs["scopes"]) del kwargs["scopes"] return BaseClient._put(self, url, form, json, buff, **kwargs) def _delete(self, url: str, **kwargs): if "scopes" in kwargs: if "headers" not in kwargs: kwargs["headers"] = {} self._set_auth_headers(kwargs["headers"], kwargs["scopes"]) del kwargs["scopes"] return BaseClient._delete(self, url, **kwargs) def _set_auth_headers(self, headers: dict, scopes: list[Scope]): if "Authorization" not in headers: auth = self.token_provider.get_token(scopes) headers["Authorization"] = "Bearer {}".format(auth["access_token"])
Ancestors
Subclasses
class OAuthTokenProvider (client_id: str, client_secret: str)
-
Helper class that automatically generates (and caches) access tokens using specific app credentials.
Create new instance of the provider.
Args
client_id
:str
- Application client ID.
client_secret
:str
- Application client secret.
Expand source code
class OAuthTokenProvider(TokenProviderInterface): """ Helper class that automatically generates (and caches) access tokens using specific app credentials. """ def __init__(self, client_id: str, client_secret: str): """ Create new instance of the provider. Args: client_id (str): Application client ID. client_secret (str): Application client secret. """ self.client_id = client_id self.client_secret = client_secret self.auth_client = AuthenticationClient() self.cache = {} def get_token(self, scopes: list[Scope]) -> str: cache_key = "+".join(map(lambda s: s.value, scopes)) now = datetime.now() if cache_key in self.cache: auth = self.cache[cache_key] if auth["expires_at"] > now: return auth auth = self.auth_client.authenticate( self.client_id, self.client_secret, scopes) auth["expires_at"] = now + timedelta(0, auth["expires_in"]) return auth
Ancestors
Inherited members
class Scope (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
Authentication scopes.
Expand source code
class Scope(Enum): """ Authentication scopes. """ USER_PROFILE_READ = "user-profile:read" """ The application will be able to read the end user’s profile data (not including associated products and services). """ USER_READ = "user:read" """ The application will be able to read the end user’s profile data, including associated products and services. """ USER_WRITE = "user:write" """ The application will be able to create, update, and delete the end user’s profile data, including associated products and services. """ VIEWABLES_READ = "viewables:read" """ The application will only be able to read the end user’s viewable data (e.g., PNG and SVF files) within the Autodesk ecosystem. """ DATA_READ = "data:read" """ The application will be able to read all the end user’s data (viewable and non-viewable) within the Autodesk ecosystem. """ DATA_WRITE = "data:write" """ The application will be able to create, update, and delete data on behalf of the end user within the Autodesk ecosystem. """ DATA_CREATE = "data:create" """ The application will be able to create data on behalf of the end user within the Autodesk ecosystem. """ DATA_SEARCH = "data:search" """ The application will be able to search the end user’s data within the Autodesk ecosystem. """ BUCKET_CREATE = "bucket:create" """The application will be able to create an OSS bucket it will own.""" BUCKET_READ = "bucket:read" """ The application will be able to read the metadata and list contents for OSS buckets that it has access to. """ BUCKET_UPDATE = "bucket:update" """ The application will be able to set permissions and entitlements for OSS buckets that it has permission to modify. """ BUCKET_DELETE = "bucket:delete" """The application will be able to delete a bucket that it has permission to delete.""" CODE_ALL = "code:all" """ The application will be able to author and execute code on behalf of the end user (e.g., scripts processed by the Design Automation API). """ ACCOUNT_READ = "account:read" """ For Product APIs, the application will be able to read the account data the end user has entitlements to. """ ACCOUNT_WRITE = "account:write" """ For Product APIs, the application will be able to update the account data the end user has entitlements to. """
Ancestors
- enum.Enum
Class variables
var ACCOUNT_READ
-
For Product APIs, the application will be able to read the account data the end user has entitlements to.
var ACCOUNT_WRITE
-
For Product APIs, the application will be able to update the account data the end user has entitlements to.
var BUCKET_CREATE
-
The application will be able to create an OSS bucket it will own.
var BUCKET_DELETE
-
The application will be able to delete a bucket that it has permission to delete.
var BUCKET_READ
-
The application will be able to read the metadata and list contents for OSS buckets that it has access to.
var BUCKET_UPDATE
-
The application will be able to set permissions and entitlements for OSS buckets that it has permission to modify.
var CODE_ALL
-
The application will be able to author and execute code on behalf of the end user (e.g., scripts processed by the Design Automation API).
var DATA_CREATE
-
The application will be able to create data on behalf of the end user within the Autodesk ecosystem.
var DATA_READ
-
The application will be able to read all the end user’s data (viewable and non-viewable) within the Autodesk ecosystem.
var DATA_SEARCH
-
The application will be able to search the end user’s data within the Autodesk ecosystem.
var DATA_WRITE
-
The application will be able to create, update, and delete data on behalf of the end user within the Autodesk ecosystem.
var USER_PROFILE_READ
-
The application will be able to read the end user’s profile data (not including associated products and services).
var USER_READ
-
The application will be able to read the end user’s profile data, including associated products and services.
var USER_WRITE
-
The application will be able to create, update, and delete the end user’s profile data, including associated products and services.
var VIEWABLES_READ
-
The application will only be able to read the end user’s viewable data (e.g., PNG and SVF files) within the Autodesk ecosystem.
class SimpleTokenProvider (access_token: str)
-
Simple implementation of
TokenProviderInterface
when you already have an access token that you want to use. When using this approach, make sure that the hard-coded access token supports all the scopes that may be needed.Create new instance of the provider.
Args
access_token
:str
- Token that will always be returned by
SimpleTokenProvider.get_token()
.
Expand source code
class SimpleTokenProvider(TokenProviderInterface): """ Simple implementation of `TokenProviderInterface` when you already have an access token that you want to use. When using this approach, make sure that the hard-coded access token supports all the scopes that may be needed. """ def __init__(self, access_token: str): """ Create new instance of the provider. Args: access_token (str): Token that will always be returned by `SimpleTokenProvider.get_token`. """ self.access_token = access_token def get_token(self, scopes: list[Scope]) -> str: return self.access_token
Ancestors
Inherited members
class TokenProviderInterface
-
Interface for any class that can provide access tokens to API clients based on a set of OAuth scopes.
Expand source code
class TokenProviderInterface: """ Interface for any class that can provide access tokens to API clients based on a set of OAuth scopes. """ def get_token(self, scopes: list[Scope]) -> str: """ Generates access token for given set of scopes. Args: scopes (list[Scope]): List of scopes that the generated access token should support. Returns: str: Access token. """ raise NotImplementedError()
Subclasses
Methods
def get_token(self, scopes: list) ‑> str
-
Generates access token for given set of scopes.
Args
scopes
:list[Scope]
- List of scopes that the generated access token should support.
Returns
str
- Access token.
Expand source code
def get_token(self, scopes: list[Scope]) -> str: """ Generates access token for given set of scopes. Args: scopes (list[Scope]): List of scopes that the generated access token should support. Returns: str: Access token. """ raise NotImplementedError()