Skip to main content

Hello,



I am trying to access my Box app with Python code, that is using JWT to authenticate. Here is my code:



from boxsdk import JWTAuth

from boxsdk import Client

from cryptography.hazmat.primitives.serialization import load_pem_private_key

import json

import base64

private_key_fpath = "/path/to/PrivatKey.pem"

#Settings below generated by the Box Developer Console

settings_fpath = "/path/to/1234__config.json"

with open(private_key_fpath, "rb") as key_file:

priv_rsakey = load_pem_private_key(key_file.read(), password=None)

with open(settings_fpath, "r") as f:

settings = json.loads(f.read())

settings['boxAppSettings']['appAuth']["privateKey"] = priv_rsakey

auth = JWTAuth.from_settings_dictionary(

settings

)

access_token = auth.authenticate_instance()



I get the following error



BoxOAuthException: 

Message: "kid" invalid, unable to lookup correct key

Status: 400

URL: https://api.box.com/oauth2/token

Method: POST

Headers: {'Date': 'Mon, 22 Apr 2024 20:27:23 GMT', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000', 'Set-Cookie': 'box_visitor_id=6626c5ed677b62.17237192; expires=Tue, 22-Apr-2025 20:27:23 GMT; Max-Age=31536000; path=/; domain=.box.com; secure; SameSite=None, bv=MONO-6104; expires=Mon, 29-Apr-2024 20:27:23 GMT; Max-Age=604800; path=/; domain=.app.box.com; secure, cn=53; expires=Tue, 22-Apr-2025 20:27:23 GMT; Max-Age=31536000; path=/; domain=.app.box.com; secure, site_preference=desktop; path=/; domain=.box.com; secure', 'Cache-Control': 'no-store', 'Via': '1.1 google', 'Alt-Svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000', 'Transfer-Encoding': 'chunked'}



Is my code missing anything?



Thanks!

Hi @alex_resolver ,



Well the error message says you’re missing the public key id, and that should be included in your config.json, or manually added as you’re doing with the private key.



For example:



{

"boxAppSettings": {

"clientID": "fe...so",

"clientSecret": "3N...i",

"appAuth": {

"publicKeyID": "39749s1s",

"privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMII...nlCE=\n-----END ENCRYPTED PRIVATE KEY-----\n",

"passphrase": "fa...c3"

}

},

"enterpriseID": "877840855",

"webhooks": {

"primaryKey": "zX...E0",

"secondaryKey": "Ew...nf"

}

}



That public key id must match what is configure in your application developer console.


For example:




My config.json was downloaded at the time of key creation. If you didn’t save that file, or created the key manually, it is ok, you can download the config.json file:





However the file will be incomplete since Box does not store your private key, and the file is also missing the key id:



For example if I download my config.json:



{

"boxAppSettings": {

"clientID": "fe...so",

"clientSecret": "3N...xi",

"appAuth": {

"publicKeyID": "",

"privateKey": "",

"passphrase": ""

}

},

"enterpriseID": "877840855",

"webhooks": {

"primaryKey": "zX...E0",

"secondaryKey": "Ew...nf"

}

}



From here I believe your have 2 options, edit your config.json and add the missing key id, or manually add the key id via settings.



You can also decide to add the private key to your config.json file, watch out for the explicit EOL \n.



On a side note, it is not clear to me if you created the private key manually, and most importantly if it is encrypted or not. Make sure it is consistent, if encrypted, then check the passphrase.



The SDK does handle the steps of reading the private key file.


You can try something like this:



from boxsdk import JWTAuth, Client



service_account_auth = JWTAuth(

client_id='YOUR_CLIENT_ID',

client_secret='YOUR_CLIENT_SECRET',

enterprise_id='YOUR_ENTERPRISE_ID',

jwt_key_id='YOUR_JWT_KEY_ID',

rsa_private_key_file_sys_path='/path/to/file/CERT.PEM',

rsa_private_key_passphrase='PASSPHRASE',

store_tokens=your_store_tokens_callback_method,

)



access_token = auth.authenticate_instance()



service_account_client = Client(auth)



Or, if the config.json is complete:



auth = JWTAuth.from_settings_file('/path/to/settings.json')

client = Client(auth)

service_account = client.user().get()

print(f'Service Account user ID is {service_account.id}')



Let us know if this helps



Best regards


Reply