Skip to main content

BoxOAuthException when using JWT

  • April 22, 2024
  • 1 reply
  • 130 views

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!

1 reply

rbarbosa Box
  • Developer Advocate
  • 553 replies
  • April 22, 2024

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


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