Level up your Box knowledge with brand new learning paths on Box University. Visit training.box.com to get started

Connect to my own Box account via Python SDK

Answered
New post

Comments

6 comments

  • Official comment
    Kourtney

    Hello Jason, 

    Since you said you're trying to write scripts for automate tasks, you will want to use JWT authentication, which does not require end-user interaction. 

    Could you clarify what you meant when you said, "I wrote the code to connect via JWT, and was able to upload and download, but then I realized that's for a special app, not the general Box account I set up." ? 

    It sounds like you may have been using the default token for a JWT app, which is the JWT service account

    If you set your apps application access to "enterprise" you can obtain a token for a regular Box user account. To do this, you'll want to ensure that the following values are set in your JWT assertion

    box_sub_type = user 

    sub = userID of the user you want a token for 

     

    Best, 

    Kourtney

    Comment actions Permalink
  • Jason Friedman

    Hello Kourtney,

    What I meant by "I wrote the code to connect via JWT, and was able to upload and download, but then I realized that's for a special app, not the general Box account I set up" is that the files I upload via the JWT service account were only visible when logged in via the JWT service account (via my Python script). They were not visible from a browser pointed at https://app.box.com/folder/0 when logged in as my user js******08@gmail.com

    So, following your instructions above I have this code:

    authentication_url = 'https://api.box.com/oauth2/token'
    user_id = "js*****08@gmail.com"

    config_file = pathlib.Path.home() / "config.json"
    config = json.load(open(config_file))
    appAuth = config["boxAppSettings"]["appAuth"]
    privateKey = appAuth["privateKey"]
    passphrase = appAuth["passphrase"]

    key = load_pem_private_key(
    data=privateKey.encode('utf8'),
    password=passphrase.encode('utf8'),
    backend=default_backend(),
    )

    claims = {
    'iss': config['boxAppSettings']['clientID'],
    'sub': user_id,
    'box_sub_type': 'user',
    'aud': authentication_url,
    'jti': secrets.token_hex(64),
    'exp': round(time.time()) + 45
    }

    keyId = config['boxAppSettings']['appAuth']['publicKeyID']
    assertion = jwt.encode(
    claims,
    key,
    algorithm='RS512',
    headers={
    'kid': keyId
    }
    )

    params = {
    'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion': assertion,
    'client_id': config['boxAppSettings']['clientID'],
    'client_secret': config['boxAppSettings']['clientSecret']
    }

    response = requests.post(authentication_url, params)
    print(response.status_code)
    print(response.text)
    which yields:
    400
    {"error":"invalid_request","error_description":"Cannot obtain token based on the enterprise configuration for your app"}
    In my app configuration I have checked "OAuth 2.0 with JSON Web Tokens" for Authentication Method, "Enterprise" for Application Access, enabled all Application Scopes, and enabled all Advanced Features.
     
    And, just to be clear, my user_id is my email address (js*****08@gmail.com) I use when logging in via a browser?
    0
    Comment actions Permalink
  • Kourtney

    Hey Jason, 

     

    Your user_id is actually going to be a unique numeric value that is assigned to each Box account. An easy way to obtain this is using the get current user endpoint, but to make this really easy for you yours is 14239712463. Let me know if you still encounter errors after changing the email address in your code to the user ID number!

     

    Best, 

    Kourtney

    0
    Comment actions Permalink
  • Jason Friedman

    Thank you for sticking with me, Kourtney. The snippet of my code that is changed:

    claims = {
    'iss': config['boxAppSettings']['clientID'],
    'sub': "14239712463",
    'box_sub_type': 'user',
    'aud': authentication_url,
    'jti': secrets.token_hex(64),
    'exp': round(time.time()) + 45
    }
    And the same result:
    400
    {"error":"invalid_request","error_description":"Cannot obtain token based on the enterprise configuration for your app"}
     
    0
    Comment actions Permalink
  • Kourtney

    No worries, Jason! We'll get you there. Can you try reauthorize your application in the admin console? If you still receive an error could you provide me with your client ID (aka API key) so I can pull some backend logs? 

    Best, 

    Kourtney

    0
    Comment actions Permalink
  • Jason Friedman

    That did it! Thank you, Kourtney.

    Three things ... first, resubmitting did not generate a new approval email, but I searched through my old email for the original one and clicked the link in that email

    Second, here's my working code for the next gal/guy who needs this:

    import cryptography
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives.serialization import load_pem_private_key
    import io
    import json
    import os
    import pathlib
    import time
    import secrets
    import boxsdk
    import requests
    import jwt

    authentication_url = 'https://api.box.com/oauth2/token'
    account_id = "00000000000" # set to your account_id
    config_file = pathlib.Path.home() / "config.json"

    config = json.load(open(config_file))

    appAuth = config["boxAppSettings"]["appAuth"]
    privateKey = appAuth["privateKey"]
    passphrase = appAuth["passphrase"]

    # https://cryptography.io/en/latest/
    key = load_pem_private_key(
    data=privateKey.encode('utf8'),
    password=passphrase.encode('utf8'),
    backend=default_backend(),
    )

    claims = {
    'iss': config['boxAppSettings']['clientID'],
    'sub': account_id
    'box_sub_type': 'user',
    'aud': authentication_url,
    'jti': secrets.token_hex(64),
    'exp': round(time.time()) + 45
    }

    keyId = config['boxAppSettings']['appAuth']['publicKeyID']

    assertion = jwt.encode(
    claims,
    key,
    algorithm='RS512',
    headers={
    'kid': keyId
    }
    )

    params = {
    'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion': assertion,
    'client_id': config['boxAppSettings']['clientID'],
    'client_secret': config['boxAppSettings']['clientSecret']
    }
    response = requests.post(authentication_url, params)
    access_token = response.json()['access_token']

    auth = boxsdk.OAuth2(
    client_id=config['boxAppSettings']['clientID'],
    client_secret='',
    access_token=access_token
    )
    client = boxsdk.Client(auth)

    root_folder = client.folder('0')
    for item in root_folder.get_items():
    my_file = client.file(file_id=item.id)
    print(my_file)

    Third, these are screenshots of my app configuration:

    Note that "account_id" above is actually User ID below.

     

     

    0
    Comment actions Permalink

Please sign in to leave a comment.