Skip to main content
Question

Custom app with JWT authentication, cannot create file in folder

  • May 23, 2025
  • 5 replies
  • 34 views

Forum|alt.badge.img

Hello,

I created a custom app with JWT authentication.

I first created a POC, writing a Python Library to create a Client based upon CLIENT_ID / CLIENT_SECRET / DEVELOPER_TOKEN.

I asked IT to get Service Account ID. I created a folder, and gave to this Service account ID co owner rights to the folder.

I could validate the upload of a file in the folder.

Now I'm trying to follow this documentation to use JWT auhtentication with Box Python SDK https://developer.box.com/guides/authentication/jwt/with-sdk/.

It appears that client creation with config.json file is OK (no error) but as soon as I try to upload file in folder I have the following error

{'errors': [{'reason': 'invalid_parameter', 'name': 'item', 'message': "Invalid value 'd_XXXXXXXXXXXX'. 'item' with value 'd_XXXXXXXXXXXX' not found"}]}

This folder is the same as first POC, so it exists, and the Service account ID has co owner rights. So why do I get this error? If anyone can help on this topic...

 

 

5 replies

Forum|alt.badge.img

Hi Julien,

I've tried to replicate your use case and I was able to upload a file. I think the source of the issue might be how the service account was added to the folder as co-owner.

If I understood correctly there are 2 service accounts. A folder owned by service account A is shared with service account B and service account B uploads a file.

In my test this worked:

Service account A in my case is name JWT, has a folder named "JWT folder for UI Sample apps"

BOX3_YHz0bl_fzcZj7Wo-t-4zmQ.png

 

I used the sharing link feature:

BOX3_HX7yPl97bN4fXlE-jkOGFA.png

BOX3_KiyMajBx7no7vOKd8-jrbw.png

 

and this python script works fine:

from boxsdk import JWTAuth, Client
from boxsdk.object.file import File


class CFG:
    """config class"""

    JWT_CONFIG_FILE = ".jwt.config.json"
    AS_USER = "18622116055"
    PARENT_FOLDER_ID = "0"  # folder id 0 is root folder


def get_box_client(as_user: bool = False):
    """get a box client"""
    auth = JWTAuth.from_settings_file(CFG.JWT_CONFIG_FILE)
    service_client = Client(auth)
    if not as_user:
        return service_client
    user = service_client.user(CFG.AS_USER)
    return service_client.as_user(user)


def print_items(items):
    """print items"""
    print("\n")
    print("Type\tID\tName")
    print("----\t--\t----")
    for item in list(items):
        print(f"{item.type}\t{item.id}\t{item.name}\t")


def main():
    """main function"""

    client = get_box_client(as_user=False)

    # print current user info
    user = client.user().get()
    print(f"Current User: {user.name}\tid:{user.id}\temail:{user.login}")

    # list files in parent folder
    items = client.folder(CFG.PARENT_FOLDER_ID).get_items()
    print_items(items)

    # folder = 198775845609

    client.folder("198775845609").upload("test_upload.txt", "test_upload.txt")


if __name__ == "__main__":
    main()
    print("\n")
    print("-" * 80)
  print("All Done!")

However, when trying to replicate your use case, I also tried to invite the UI Elements service account as a co-owner collaborator to another folder, and the invite is pending acceptance from that service account, which in my case has no valid email.

BOX3_EIJDvdhEyA9DsDXQrBaKvA.png

BOX3_VNdoV3x4pUpKG-B2H2ltug.png

Could this be the source of your issue?


Forum|alt.badge.img

Hello Rui and thanks for this very clear answer.

First to answer your question, yes I think you understood the issue

"If I understood correctly there are 2 service accounts. A folder owned by service account A is shared with service account B and service account B uploads a file."  ==> if you consider my personal account is a "service account" which I'm not sure regarding Box terminology

I finally found a solution on my side :

- with Python API, create a new folder with Client authenticated with app config file (using create_subfolder)

- share this with folder with my personal account so that I can have access to that folder (.add_collaborator("mail@mail.com", CollaborationRole.CO_OWNER)

Since, I can now use this folder to CRUD file without any problem with authentication with config file.

But I still can't use the folder I created with my personal account, which I then shared with app Service Account.

The hypothesis you raised regarding the "Pending" sharing is interesting, it might be root cause of issue, as it seems to be some access right management issue. But you have to know I don't have this view when checking information regarding the sharing.

If it helps, here are the folder I created

The folder with which I have an issue (the one created with my account then shared)

https://harmonicinc.app.box.com/folder/196886012101

BOX3_nZH39Hizc1KbRqEuKK_TDQ.png

The folder which works fine (created with app service account then shared with my personal account)

https://harmonicinc.app.box.com/folder/198717991676

BOX3_jEOq0KpDMvobhCXcfwLDrw.png

Strangely, the folder has been created with "Box Admin Service Account" while I was expecting it to be created with the app service account (Box_XOS_manufacturing). Since I'm using the config.json file from the app, I would have expected to always have a client which is using "Box_XOS_manufacturing" for any command.

But it looks like that once client is created with same config.json file :

- we send upload commands with "Box_XOS_manufacturing"  account

- we send create_subfolder commands with  "Box Admin Service Account"

 


Forum|alt.badge.img

BTW I reused your python library to redo the test with my own folder/accounts and problem is the same.


Forum|alt.badge.img

Hi Julien,

That is odd indeed...

So looking at your screenshots I can see both folders are shared with different service users, which is puzzling, and leads me to think there are 2 service users.

Perhaps the person acting as the box administrator in your company did something manually or has some policies in place.

Once an app is using JWT authentication the service user should be consistent, these apps, depending on configuration, can impersonate another user but not another service app.

To be honest, what you're describing is somewhat unexpected, but there are so many variables in play, that I lost track. I'm glad you found a workaround.

However here are some of the more generic rules and my configurations, perhaps these can help you identify your situation.

You can check these under the developer console for your specific app (https://app.box.com/developers/).

So in my example I have an app configure to authenticate using JWT (server side):

BOX3_pWJ6bmHq5eS6XNUg9bKs3A.png

 

Then on the app access level it is configured as app+enterprise access, giving it access to the entire enterprise:

 

BOX3_hMc2DHU3h2L7m7jX0c8UpA.png

 

On application scopes I have everything selected, and on the advanced features I have:

BOX3_O271BdcBjCfxNOWaJm8G5A.png

This will allow this service user to impersonate any other user in the enterprise.

There is an interesting detail here. If you set a developer token that usually only lasts for 60 minutes, that token is associated with your user rather than the service user.

BOX3_uYh70nnwYx1TChy4VOoZIw.png

Every time you change something here you need to ask you box administrator to reauthorize the app, you can check its status or submit via the authorization tab:

BOX3_I1t7HeXQPJnR8i0XbxCYbw.png

Another test you can do is check which user represents the service account associated with the JWT, for my previous example:

    client = get_box_client(as_user=False)

    # print current user info
    user = client.user().get()
    print(f"Current User: {user.name}\tid:{user.id}\temail:{user.login}")

    # list files in parent folder
  items = client.folder(0).get_items()
    print_items(items)

outputs, the service user details and the items of the root folder:

Current User: 
UI-Elements-Sample        
id:20344589936  
email:AutomationUser_1841316_RbcnIM9B2l@boxdevedition.com


Type    ID      Name
----    --      ----
folder  177388203339    100k
folder  172599089223    Bookings
folder  163422716106    Box UI Elements Demo
folder  189803765719    ClassificationService
folder  198775845609    JWT Folder for UI Sample Apps
folder  172611202270    My Signed Documents
folder  170845975022    Waivers
folder  176837925976    Webhook

You can also list all the users visible to your service user:

    users = client.users()
    for user in users:
        print(f"User: {user.name}\tid:{user.id}\temail:{user.login}")

which outputs in my case:

User: Administrator     id:18662105676  email:AppUser_1715931_Il2dcyHuqu@boxdevedition.com
User: Administrator     id:18662356345  email:AppUser_1715931_vt8XOps1Ff@boxdevedition.com
User: Administrator     id:18661971368  email:AppUser_1715931_xSifhdw6W7@boxdevedition.com
User: Investment User   id:22240548078  email:barduinor+inv@gmail.com
User: Wealth User       id:22240405099  email:barduinor+we@gmail.com
User: Wholesale User    id:22240545678  email:barduinor+wh@gmail.com
User: Rui Barbosa       id:18622116055  email:barduinor@gmail.com

From here you can create a folder and share it with your personal user and verify how does it show up on your side.

    # create a new folder
    folder_new = client.folder(CFG.PARENT_FOLDER_ID).create_subfolder("Shared with RB")

    # share it with RB as co-owner
    folder_new.add_collaborator("barduinor@gmail.com", CollaborationRole.CO_OWNER)

Now when I login as myself on the box app, I can see the folder owned by the service user which created it:

BOX3_Vy-B_8bgUHXteFygtVdYQA.png

Now, lets upload a file, again using the app service user to this folder which in my case is:

Type    ID      Name
----    --      ----
folder  177388203339    100k
folder  198947288178    aaaa
folder  172599089223    Bookings
folder  163422716106    Box UI Elements Demo
folder  189803765719    ClassificationService
folder  198775845609    JWT Folder for UI Sample Apps
folder  172611202270    My Signed Documents
folder  198948099055    Shared with RB
folder  170845975022    Waivers
folder  176837925976    Webhook

using this:

client.folder("198948099055").upload("test_upload.txt", "test_upload.txt")

And the file is also owned by the service user:

BOX3_wNaePDxYBOo0vMt-TI6eYA.png

 

Hope this helps you test your use case and find out why we can see 2 distinct service users.

Best regards


Forum|alt.badge.img

Hello Rui,

Regarding the suggested app parameters, I do have same authentication as you have.

I also tested :

- app access level (it was App acc only for me)

- advanced features (it was no ticked for both paremeters, I ticked the boxes)

but no effect, still have the issue.

Regarding the following test

client.user().get()

I have following error message

Context Info: {'errors': [{'reason': 'invalid_parameter', 'name': 'user', 'message': "Invalid value 'u_217074553'. 'user' with value 'u_217074553' not found"}]}

For the client.users() request it does not print anything.

It looks like that either i don't have rights to get users for client, or there are no users...

I only see this log trace 

boxsdk.pagination.limit_offset_based_object_collection.LimitOffsetBasedObjectCollection 

I tried several things, like managing exception and so on, but still hve nothing print

        try:
            user_iterator = self.client.users()
        except BoxAPIException as e:
            print(f"Error fetching user list: {e}")
            exit()

        # Loop through all users
        for user in user_iterator:
            if isinstance(user, User):
                print(user.name, user.login)
            else:
                print(f"Skipping non-user object: {user}") 

The create_subfolder / add_collaborator proposed test is what I did as a workaround and I do confirm it works fine and this now what I'm using.