Employees authorising API

Hey All,

How do we make an API call without using the ‘Bb-Api-Subscription-Key’??

My program uses the applications ID etc to get the user to authorise it. And then returns the bearer token. However, I assume that bearer token would be unique to their “key”.

How would i make the call using these new credentials?
See some of current code below

def step2(auth_code):

global access_token, refresh_token, hdr

# Step 3: Exchange the authorization code for an access token

token_url = 'https://oauth2.sky.blackbaud.com/token'

payload = {

'grant_type': 'authorization_code',

'code': auth_code,

'client_id': client_id,

'client_secret': client_secret,

'redirect_uri': redirect_uri,

'preserve_refresh_token': True #

}


# Make the POST request to get the token

response = requests.post(token_url, data=payload)

response_data = response.json()


if 'access_token' not in response_data:

print(f'Error: {response_data.get("error_description")}')

else:

access_token = response_data['access_token']

refresh_token = response_data['refresh_token']

print(f'Access token received: {access_token}\\nRefresh token: {refresh_token}')


# Update the global header with the obtained access token

hdr = {

'Content-Type': 'application/json',

'Cache-Control': 'no-cache',

'client_id': client_id,

'client_secret': client_secret,

#'Bb-Api-Subscription-Key': ''", # I use this in my testing and also works for me when I authorise it. However doesnt for other users

'Authorization': f'Bearer {access_token}'

}


# Signal that step2 is complete

token_event.set()


Comments

  • @Hamish Burnett

    I mentioned recently in an older post you may have missed that you can use my class in this repo, there is a script in there using the query endpoint too, to look at as an example - but you need create an application first in your your developer.blackbaud.com account - There is no way around needing the application.

    Once you have the application and token/keys - ‘pip install keyring’ or ‘pipenv install keyring’ if using a venv - This is setup securing your token/keys. You would then use it something this in your script

    from bb_auth import BlackbaudAuth
    def main():
    # Initialize authentication (automatically retrieves stored tokens or prompts for login)
    auth = BlackbaudAuth()

    # Get an authenticated session
    session = auth.get_session()

    # Example API request using the authenticated session
    endpoint = "/some_endpoint"
    response = session.get(f"https://api.sky.blackbaud.com{endpoint}")

    if response.ok:
    print("Request successful:", response.json())
    else:
    print("Request failed:", response.status_code, response.text)
    if __name__ == "__main__":
    main()

    This will give you:

    • Persistent Token Storage: It securely stores and retrieves OAuth tokens using keyring, eliminating the need expose and copy/paste keys.
    • Automatic Token Refresh: When an access token expires, bb_auth automatically refreshes it using the stored refresh token.
    • OAuth Callback Handling: It includes a built-in HTTP server (OAuthCallbackHandler) to handle the OAuth redirect flow, so you don't need to manually copy and paste keys.
    • Encapsulation & Reusability: The BlackbaudAuth class is structured to be used across multiple scripts - taking care all authentication



  • @Bryce Howard
    Cheers,
    And wanting to clarify, then anyone in the org can authorise and run the code?

    Where is it pulling ‘Bb-Api-Subscription-Key’ from?

  • or does everyone just use my subscription key?

  • @Hamish Burnett

    • Bb-Api-Subscription-Key is associated with your org (site id) that is under
      • Developer account>My subscriptions:
        • ‘Primary access key’ or ‘Bb-Api-Subscription-Key’
    • You create the application
      • Developer account>My applications:
        • client_id and client_secret
    • Then you give access to users, which is why you sign-in during auth process:
      • Each user gets their own access_token which needs refreshing, that is when the exchange happens using refresh_token

    More info here