Ok also something else super wierd while digging into this:
On the Left is my Prod console. On the Right is my Devconsole:
As I was comparing them to make sure I didnt miss anything, um, why is there different text in these boxes. They are configured exactly the same with the single exception being the PublicKey Pair.
Does this indicate something?!
Hi @AndrewC , welcome to the forum!
You can absolutely do a manual HTTP POST request to get a new access token.
The issue might be how to generate a JWT assertion that you must include in that request.
For example in our postman collection, we have this pre-request script for getting and access token using JWT:
async function refresh_jwt (assertion) {
const urlencoded = [
{ key: 'client_id', value: pm.environment.get('client_id'), disabled: false },
{ key: 'client_secret', value: pm.environment.get('client_secret'), disabled: false },
{ key: 'box_subject_type', value: pm.environment.get('box_subject_type'), disabled: false },
{ key: 'box_subject_id', value: pm.environment.get('box_subject_id'), disabled: false },
{ key: 'grant_type', value: 'urn:ietf:params:oauth:grant-type:jwt-bearer', disabled: false },
{ key: 'assertion', value: assertion, disabled: false }
]
return await get_token(urlencoded).then((data) => {
const expires_at = Date.now() + (data.expires_in - 30) * 1000
pm.environment.set('access_token', data.access_token)
pm.environment.set('expires_at', expires_at)
})
}
and we create the assertion like this:
// libJSRSASign lib
const libJSRSASign = pm.collectionVariables.get('libJSRSASign')
/* eslint-disable no-global-assign */
navigator = {}
window = {}
/* eslint-disable no-eval */
eval(libJSRSASign)
// UUID
const uuid = require('uuid')
const private_key_encrypted = pm.environment.get('private_key_encrypted').replace(/\\n/g, '')
const private_key_passphrase = pm.environment.get('private_key_passphrase')
const private_key = KEYUTIL.getKey(private_key_encrypted, private_key_passphrase)
const kid = pm.environment.get('key_id')
const iss = pm.environment.get('client_id')
const sub = pm.environment.get('box_subject_id')
const box_sub_type = pm.environment.get('box_subject_type')
const aud = 'https://' + pm.collectionVariables.get('api.box.com') + '/oauth2/token'
const jti = uuid.v4()
// const exp = KJUR.jws.IntDate.get("now + 1minute")
const exp = Math.floor(Date.now() / 1000) + 45
const iat = KJUR.jws.IntDate.get('now')
const header = { alg: 'RS512', typ: 'JWT', kid: kid }
// console.log(`header: ${JSON.stringify(header)}`)
const claims =
{
iss: iss,
sub: sub,
box_sub_type: box_sub_type,
aud: aud,
jti: jti,
exp: exp,
iat: iat
}
// console.log(`claim set: ${JSON.stringify(claims)}`)
const jwt = KJUR.jws.JWS.sign(null, header, claims, private_key)
// console.log('JWT Assertion: ', jwt)
return jwt
}
This is javascript inside Postman, so it might not be that helpful, but it does illustrate the process.
However I do have a rust example for you…
Fair warning, this is incomplete, poorly implemented, and not supported! you have been warned 😉
https://crates.io/crates/rusty-box
In the examples you’ll find:
// use cargo run --example users_main to run this file
// use dotenv;
use rusty_box::{
auth::auth_jwt::JWTAuth,
auth::auth_jwt::SubjectType,
client::{box_client::BoxClient, client_error::BoxAPIError},
config::Config,
rest_api::users::users_api,
};
use std::env;
#/tokio::main]
async fn main() -> Result<(), BoxAPIError> {
dotenv::from_filename(".jwt.env").ok();
let client_id = env::var("CLIENT_ID").expect("CLIENT_ID must be set");
let client_secret = env::var("CLIENT_SECRET").expect("CLIENT_SECRET must be set");
let env_subject_type = env::var("BOX_SUBJECT_TYPE").expect("BOX_SUBJECT_TYPE must be set");
let box_subject_type = match env_subject_type.as_str() {
"user" => SubjectType::User,
"enterprise" => SubjectType::Enterprise,
_ => panic!("BOX_SUBJECT_TYPE must be either 'user' or 'enterprise'"),
};
let box_subject_id = env::var("BOX_SUBJECT_ID").expect("BOX_SUBJECT_ID must be set");
let public_key_id = env::var("PUBLIC_KEY_ID").expect("PUBLIC_KEY_ID must be set");
let encrypted_private_key =
env::var("ENCRYPTED_PRIVATE_KEY").expect("ENCRYPTED_PRIVATE_KEY must be set");
let passphrase = env::var("PASSPHRASE").expect("PASSPHRASE must be set");
let config = Config::new();
let auth = JWTAuth::new(
config,
client_id,
client_secret,
box_subject_type,
box_subject_id,
public_key_id,
encrypted_private_key,
passphrase,
);
let mut client = BoxClient::new(Box::new(auth));
let fields = vec!v];
let me = users_api::me(&mut client, Some(fields)).await?;
println!("Me:\n{me:#?}\n");
Ok(())
}
As for any differences on your environments, from the info you sent, I can’t see anything wrong with it. Of course I’m assuming you have a specific config.json file for each environment…
Hope this helps
Cheers