Skip to content

Instantly share code, notes, and snippets.

@wallabyway
Last active July 12, 2024 00:15
Show Gist options
  • Save wallabyway/3efdaf7ab52368cd019678b027055bd1 to your computer and use it in GitHub Desktop.
Save wallabyway/3efdaf7ab52368cd019678b027055bd1 to your computer and use it in GitHub Desktop.
SSA Token generator on Lambda (minimal)

Generate 3LO SSA Tokens from Lambda

SETUP

  1. Create a new AWS Lambda function (arm64), make it public, and copy this code into lambda_function.py
  2. Set the environment variables
  3. Add jwt library dependency
  4. Click Deploy and then click Test

2. Environment Variables

Go to Console->Configuration->Env. and add inputs:

APS_clientID, APS_secretID, SSA_oxygenID, kid, private_key

Similar to this CLI command:

export APS_clientID="your_client_id"
export APS_secretID="your_secret_id"
export SSA_oxygenID="your_oxygen_id"
export kid="your_key_id"
export private_key="your_private_key"
export SCOPE="data:read data:write"

3. Add jwt Library Dependency to the Function

This seperates future source code changes, from the jwt library dependency, without uploading new package.zip files constantly.

You need to create a python library dependency zip file first, and then add it to the function as a layer.

Here are the Steps:

  • a. Create the zip file
mkdir my-lambda-function
cd my-lambda-function
pip3 install \
    --platform manylinux2014_aarch64 \
    --target=python/lib/python3.12/site-packages \
    --implementation cp \
    --python-version 3.12 \
    --only-binary=:all: --upgrade \
    PyJWT requests cryptography
    
zip -r python_dependencies.zip python
  • b. Create a new layer Lambda function -> 'layer'
  • c. Upload the python_dependencies.zip file into the layer
  • d. choose ARM64 and Python3.12 platform dependencies, use name 'pyArmLibs'
  • e. Go back to Function and 'Add Layer', select 'pyArmLibs' and v1.
# https://gist.github.com/wallabyway/3efdaf7ab52368cd019678b027055bd1
import jwt
import time
import requests
import os
def generate_jwt_assertion(kid, private_key, APS_clientID, SSA_oxygenID, scope):
current_time = int(time.time())
claims = {
"iss": APS_clientID,
"sub": SSA_oxygenID,
"aud": "https://developer.api.autodesk.com/authentication/v2/token",
"exp": current_time + 300,
"scope": scope
}
return jwt.encode(claims, private_key, algorithm="RS256", headers={"alg": "RS256", "kid": kid})
def get_access_token(jwt_assertion, APS_clientID, APS_secretID, scope):
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
payload = {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_assertion,
'scope': ' '.join(scope)
}
response = requests.post('https://developer.api.autodesk.com/authentication/v2/token', headers=headers, data=payload, auth=(APS_clientID, APS_secretID))
return response.json()
def lambda_handler(event, context):
APS_clientID = os.environ['APS_clientID']
APS_secretID = os.environ['APS_secretID']
SSA_oxygenID = os.environ['SSA_oxygenID']
kid = os.environ['kid']
private_key = os.environ['private_key'].replace('\\n', '\n')
scope = os.environ['SCOPE'].split()
jwt_assertion = generate_jwt_assertion(kid, private_key, APS_clientID, SSA_oxygenID, scope)
access_token_response = get_access_token(jwt_assertion, APS_clientID, APS_secretID, scope)
return {'statusCode': 200, 'headers': {'Content-Type': 'application/json'}, 'body': access_token_response}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment