Skip to main content

I created a custom APP and able to run APIs from Postman without any errors.


When I try to run from typescript, I am able to run API calls to get an access token. But when I run list folder items api call it fails with 404 error - not found. I also added ‘as_user’ to the header of request, but still getting the same error. What am I missing?


The API call works with Developers Token. When I use Access Token the above APIs don’t work and return 404 error.


Very much appreciate your responses.

Hello!



The not_found error almost always occurs when the user making the call doesn’t have access to the content you are trying to make an API call for.



The as user header requires you to have the as-user header option selected for the app in the developer console and authorized by the primary admin of your enterprise Box instance.



You also need to pass in the user id of a user that has access to the content you are trying to make the call for. I don’t know enough specifics about your application set up, but let me type out an example flow.



For a JWT application, you would need to check the box on the application configuration screen in the developer console. An admin would need to authorize the application again, if this isn’t already done. After a JWT app is authorized the first time by the primary admin, a service account is automatically created. Any time the application creates a token, the user attached to the token would be the service account. If the service account hasn’t been collaborated into the content you are trying to access, you will get a not_found. A developer token is different. That token is based on the user creating the token - for example your user account.



Hope this helps,


Alex, Box Developer Advocate


Hi Alex,


Thank you for your response. I have a custom app. We just need to access files from BOX folder through API calls. I’m using typescript and axios. If I just call API (https://api.box.com/oauth2/token), it returns token, but later on when I tried to access folder through API calls it returns the error message 404 Not Found. The fact that developers token works tells me that it’s an authentication issue. I saw the explanation that I need to run Authorization API to obtain Authorization Code and then pass this code the API call to get Access Token API. But it doesn’t work. Are you saying that our BOX Admin should Authorize my App first and that will allow me to get proper Access Code? How do I obtain the service account after authorization by Admin?


Thank you for your help!


When you create a JWT or CCG type of custom application, an admin has to authorize it. They also have to reauthorize if you’ve made any changes to the permissions and scopes in the developer console.



If you use one of our published SDKS, the authentication is done for you behind the scenes if you follow the sample code examples.



We don’t currently have a TS sdk. The SDK team is working on one for the future though!



If you want to authenticate without a SDK and a JWT app, you would want to follow the steps here.



For the service account, the email address thats created appears on the general settings tab of an application in the developer console. You can take this email and simply collaborate it into the content you are trying to access via the api.






Hi Alex,


We’re using AWS lambda with typescript and axios.


As you mentioned, we can’t use box SDK since it’s only javascript.



Let’s say Admin approved our custom app.


Can I just run Authentication API call (‘/oauth2/token’) with Client Id, Client Secret and as_user to get access token? Instead of using private-public key pair with config.json file and creating JWT assertion as described HERE?



Also, it’s a little confusing with custom apps creation. At first I created the Custom APP with OAuth2.


I was able to connect to this App from developer.box.com to fork a collection to postman.



Now I created another Custom APP with JWT. I can no longer connect to this app box dev site.


It gives and Error: redirect_uri_mismatch. Is this the App I should use?



What is the best Custom App Authentication should use OAuth2, JWT or CCG to connect from AWS Lambda to read the file content and process it? I prefer to use just client id and client secret.


Of course it should be secure authentication.



Thank you




For OAuth 2 apps, they don’t need approved by the admin (by default - an admin could have the a setting flipped that requires approval) and do not get a service account attached. For that app type, you would need to use this endpoint to have the user authorize the Box api and scopes setup for your application in the developer console. It returns a code, that you have to use very quickly with this endpoint to get a token for the user that authorized the api. You can then use that token in subsequent calls. Note - the redirect uri sent along in the first api call must match the one configured in the developer console. You can find the guide on using an OAuth flow without SDKs here.



If you want to use JWT, you would need to follow the guide I linked earlier. You cannot just send in the client id and secret. If that is what you want to do, I would recommend the CCG app type. This allows you to use just the client id and secret as described here. With CCG, make sure the client id and secret remain secret as that is the only barrier to get access to your Box environment.




I tried to use OAuth2 app. I made an API call to get authorization code so I would use it to get access token, but API request would return HTML steam instead of auth. code. Here’s the code I was using:





const options = {


headers: { ‘Content-Type’: ‘application/json’ },


Cookie: ‘box_visitor_id=648771cbaf5954.11112322; site_preference=desktop’


};


const clientId = config.box.ClientId;


const url =


https://account.box.com/api/oauth2/authorize?response_type=code&client_id=${clientId};


const response = await axios.get(url, options);


console.log(response.data);


return response.data;



Was my logic wrong? Is this designed for Web Applications and not for data integrations? Our data integration functionality does not have any Web UI or user interactions.



Also which is more secure OAuth2 or JWT?


Hi @user19



Both OAuth2 and JWT are considered secure, and are adopted by many API’s as authentication methods.


However they server very different purposes.



OAuth2 purpose is for a registered user (human) to authorize an application to do “things” on behalf of the user. This mean the application will gain the security context of the user.



JWT purpose is for the application to have its own security context via a service account (non-human)



For OAuth2 to works, human intervention is necessary, and the access tokens obtained are specific for that and each user.



That is why you’re getting that HTML.


You see the first step in OAuth2 is for the user to authorize the application. For that the use must first login to the resource (in our case, Box), and then specifically authorize the app.



The authorize URL does exactly that.



Here is an example:



https://account.box.com/api/oauth2/authorize

?state=box_csrf_token_VA9p2RrCjxH6zn4V

&response_type=code

&client_id=by3om7ketll509spen1pymytg5k9hihm

&redirect_uri=http%3A%2F%2F127.0.0.1%3A5000%2Fcallback



Which looks like this on the browser:




Once the user logs in it presents the option to authorize the app, clearly explaining to the user all the permissions it requires:




Once the user grants or rejects the authorizations, the browser is the redirected to the callback so that your application can proceed and request an access token.



Continuing the example from above:




Let’s look at the URL in detail:



http://127.0.0.1:5000/callback

?state=box_csrf_token_VA9p2RrCjxH6zn4V

&code=k1O2mK0t1NcolYqnAe8n3ExxTsaqFgmV



The base URL is the same used in the original request as redirect_url, although redirect url was originally enconded:


&redirect_uri=http%3A%2F%2F127.0.0.1%3A5000%2Fcallback



The state is also the same, and allows your application to check if the request originated from it self:


?state=box_csrf_token_VA9p2RrCjxH6zn4V



Once your application verifies that the state sent is the same as the state received, it can use the code to request an access token. For example:



curl --location 'https://api.box.com/oauth2/token' \

--header 'Content-Type: application/x-www-form-urlencoded' \

--data-urlencode 'grant_type=authorization_code' \

--data-urlencode 'client_id=by3om7ketll509spen1pymytg5k9hihm' \

--data-urlencode 'client_secret=Tqb...38' \

--data-urlencode 'code=k1O2mK0t1NcolYqnAe8n3ExxTsaqFgmV'



resulting in something like:



{

"access_token": "c3FIOG9vS...k9qUE1BVQ",

"expires_in": 3600,

"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",

"refresh_token": "c3FIOG9vS...k9qUE1BVQ",

"token_type": "bearer"

}



And this is how you get an access token using OAuth2.



Cheers


It looks JWT authentication with private/public key-pair is more suitable for our data integration.



Is this supported for TypeScript? We’re using AWS lambda with typescript.


I can see the sample code in box documentation written in javascript and requires additional NPM



const crypto = require("crypto");



const jwt = require('jsonwebtoken')



Do you have any diagrams for JWT authentication to see how it works?



Thank you


Hi @user19



Humm, I’m not versed in type script…



See if this generic documentation helps:





Cheers


Hi @user19 ,



I got some interesting news.



The SDK team is releasing a Type Script SDK in August.



Not sure if you can wait that long, but it is coming.



Here is a preview of the JWT Authentication documentation:



JWT Auth



Before using JWT Auth make sure you set up correctly your Box App. The guide with all required steps can be found here: Setup with JWT



Authenticate Enterprise



JWT auth allows your application to authenticate itself with the Box API for a given enterprise. By default, your application has a Service Account that represents it and can perform API calls. The Service Account is separate from the Box accounts of the application developer and the enterprise admin of any enterprise that has authorized the app — files stored in that account are not accessible in any other account by default, and vice versa.



If you generated your public and private keys automatically through the Box Developer Console, you can use the JSON file created there to configure your SDK instance and create a client to make calls as the Service Account. Call one of static JwtAuth method: JwtConfig.fromConfigFile(configFilePath) and pass JSON file local path or JwtConfig.fromConfigJsonString(configJsonString) and pass JSON config file content as string.



const { Client } = require('BoxSDK/lib/client.generated.js'); 

const { JwtAuth, JwtConfig } = require('BoxSDK/lib/jwtAuth.js');



const jwtConfig = JwtConfig.fromConfigFile('/path/to/settings.json');

const jwtAuth = new JwtAuth({ config: jwtConfig });

const client = new Client({ auth: jwtAuth });

const me = await client.users.getUserMe();

console.log(`My user ID is ${me.id}`);



Otherwise, you’ll need to provide the necessary configuration fields directly to the JwtConfig constructor:



const { Client } = require('BoxSDK/lib/client.generated.js'); 

const { JwtAuth, JwtConfig } = require('BoxSDK/lib/jwtAuth.js');



const jwtConfig = new JwtConfig({

clientId: 'YOUR_CLIENT_ID',

clientSecret: 'YOUR_CLIENT_SECRET',

jwtKeyId: 'YOUR_JWT_KEY_ID',

privateKey: 'YOUR_PRIVATE_KEY',

privateKeyPassphrase: 'PASSPHRASE',

enterpriseId: 'YOUR_ENTERPRISE_ID',

});



const jwtAuth = new JwtAuth({ config: jwtConfig });

const serviceAccountClient = new Client({ auth: jwtAuth });



Hope this helps


Cheers


Hi,


Thank you so much for your responses. I am not sure if we can wait until Type Script SDK is released, but this a good information.



We are looking to download a file and there’s API that does it.


We would also need to move this file to another BOX folder after our data integration finished processing it. Can you please direct us to the API that move file to another folder?



Thank you for your help!


Vadim


Hi @user19



You just need to update the file with the new parent folder.



See API here.



Cheers


I tried and it works.


Thank you


You’re most welcome Vadim


Reply