Skip to main content
Solved

Get authentication token via JWK/JWT

  • October 21, 2024
  • 3 replies
  • 103 views

tva
Contributor
Forum|alt.badge.img+12
  • Contributor

I need to connect to an api that requires a bearer token in the header for authentication.

This token should be generated with a jwk.

 

Example to request a token (there are public available examples from the service, so no secrets from my side):

POST /op/v1/token HTTP/1.1
Host: authenticatie.vlaanderen.be
Content-Type: application/x-www-form-urlencoded

  grant_type=client_credentials&
  audience=8ed36a78-8443-11ec-b334-83e86b606670&
  audience=9e6a512c-8443-11ec-ae2c-8700eb2a0cde&
  scope=org_api_appread%20org_api_appwrite&
  client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
  client_assertion=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIyODM1ODgxNC01YzIwLTRjMTMtYmJmZi1kYjVkZDhjNGFlOTMiLCJzdWIiOiIyODM1ODgxNC01YzIwLTRjMTMtYmJmZi1kYjVkZDhjNGFlOTMiLCJhdWQiOiJodHRwczovL2F1dGhlbnRpY2F0aWUudmxhYW5kZXJlbi5iZS9vcCIsImV4cCI6MTU5MjIwODA2MCwianRpIjoiRGt6bmpzdTQzZHprZDN6amQ1IiwiaWF0IjoxNTkyMjA4MDAwfQ.3dPodaVhJ2d3cXWn0v2YGeZqs5XScJF2lm4MaweDnf4

 

the client assertion is a jwt that contains the following:
 

{
  "iss": "28358814-5c20-4c13-bbff-db5dd8c4ae93",
  "sub": "28358814-5c20-4c13-bbff-db5dd8c4ae93",
  "aud": "https://authenticatie.vlaanderen.be/op",
  "exp": 1592208060,
  "jti": "Dkznjsu43dzkd3zjd5",
  "iat": 1592208000
}

 

The client assertion is an encrypted string where a private key (a pem file) is used to encode the jwt.

Is there a way this can be achieved in FME? Currently this is done in an old python script so looking for a way to either achieve this in FME or looking into upgrading the python script.

(used python libs are pyjwt & cryptography)

Best answer by hkingsbury

Not that i’ve had to authenticate with an API like this previously, but it is something you’d need to do in Python. I would suggest you submit an idea for this: https://community.safe.com/ideas

 

the pyjwt library isn’t a default library that's part of FMEs Python, so you would either need to install that, or create it using default libraries (see below for an example - thanks ChatGPT). You cna use the PythonCaller transformer to include Python code into your workspace.

 

import base64
import hmac
import hashlib
import json

# Helper function for Base64Url encoding
def base64url_encode(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')

# Helper function for Base64Url decoding
def base64url_decode(encoded_data: str) -> bytes:
    padded_data = encoded_data + '=' * (4 - len(encoded_data) % 4)
    return base64.urlsafe_b64decode(padded_data)

# Create JWT Header and Payload
header = {
    "alg": "HS256",  # HMAC using SHA-256 hash algorithm
    "typ": "JWT"
}

payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "admin": True
}

secret = "your-256-bit-secret"

# Encode Header and Payload
encoded_header = base64url_encode(json.dumps(header).encode())
encoded_payload = base64url_encode(json.dumps(payload).encode())

# Create the Signature
message = f"{encoded_header}.{encoded_payload}".encode()
signature = hmac.new(secret.encode(), message, hashlib.sha256).digest()
encoded_signature = base64url_encode(signature)

# Create JWT Token
jwt_token = f"{encoded_header}.{encoded_payload}.{encoded_signature}"
print(jwt_token)

 

View original
Did this help you find an answer to your question?

3 replies

hkingsbury
Celebrity
Forum|alt.badge.img+53
  • Celebrity
  • Best Answer
  • October 21, 2024

Not that i’ve had to authenticate with an API like this previously, but it is something you’d need to do in Python. I would suggest you submit an idea for this: https://community.safe.com/ideas

 

the pyjwt library isn’t a default library that's part of FMEs Python, so you would either need to install that, or create it using default libraries (see below for an example - thanks ChatGPT). You cna use the PythonCaller transformer to include Python code into your workspace.

 

import base64
import hmac
import hashlib
import json

# Helper function for Base64Url encoding
def base64url_encode(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')

# Helper function for Base64Url decoding
def base64url_decode(encoded_data: str) -> bytes:
    padded_data = encoded_data + '=' * (4 - len(encoded_data) % 4)
    return base64.urlsafe_b64decode(padded_data)

# Create JWT Header and Payload
header = {
    "alg": "HS256",  # HMAC using SHA-256 hash algorithm
    "typ": "JWT"
}

payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "admin": True
}

secret = "your-256-bit-secret"

# Encode Header and Payload
encoded_header = base64url_encode(json.dumps(header).encode())
encoded_payload = base64url_encode(json.dumps(payload).encode())

# Create the Signature
message = f"{encoded_header}.{encoded_payload}".encode()
signature = hmac.new(secret.encode(), message, hashlib.sha256).digest()
encoded_signature = base64url_encode(signature)

# Create JWT Token
jwt_token = f"{encoded_header}.{encoded_payload}.{encoded_signature}"
print(jwt_token)

 


tva
Contributor
Forum|alt.badge.img+12
  • Author
  • Contributor
  • October 22, 2024

Thanks for the information, I will suggest an idea about this. Funny thing, copilot (as chat gpt isn’t allowed in the company as it uses the prompt to train itself further, while copilot claims it doesn’t (when logged in)) gives something different but similar :)

It works in my use case so now I have a miniconda env with the necessary python lib, as I’m not a big fan on installing extra python stuff in the FME python folder).

The scripts generates a textfile that contains my bearer token which I read via attribute file reader. I’ve put this in a custom transformer so that I can re-use it where I need it.

 

Brings me to the next challenge: I got a timeout on the bearer of 1 hour. I need to do thousands of api calls (need to fetch 300k features while the limit per call is 100). So wondering what the best approach would be here as I don’t want to use the CT every api call (seems a bit a lazy approach and generates overhead at my side but also at server side).
So using the http caller with multiple threads will speed up the process, but as soon as I pass the hour I’ll get 401 errors. 

So does someone have an idea on how to do this kind of looping but still have multi threaded api calls?


tva
Contributor
Forum|alt.badge.img+12
  • Author
  • Contributor
  • October 22, 2024

Edit, will post this as a new question


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings