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 ![:wink: :wink:](https://emoji.discourse-cdn.com/twitter/wink.png?v=12)
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![];
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