In today’s digital world, we often use multiple online services that require access to our personal information or resources from other applications. However, sharing our login credentials with third-party applications can be risky. That’s where OAuth 2.0 comes in.
OAuth 2.0 is an authorization framework that allows you to grant limited access to your resources on one application to another application without sharing your login credentials. It functions as a secure intermediary, granting third-party apps limited access to your account information through authorized tokens.
Here’s a simple example of OAuth: imagine you want to log into a new app using your Google account. Instead of providing your Google username and password to the app, you can use OAuth. The app will redirect you to Google, where you can log in and grant the app permission to access specific parts of your Google account, such as your email address or profile information. Google then sends an access token to the app, which it can use to access the authorized information.
In this blog post, we’ll explore the key concepts of OAuth 2.0, including the roles involved, various flows, the different types of tokens used in the process, and how you can use BoldSign OAuth 2.0 to integrate with your applications in different scenarios.
Roles in OAuth 2.0
It is important to understand the roles involved in the OAuth process that interact with each other to facilitate secure authorization:
- You, the User (aka Resource Owner): As the resource owner, you have the power to grant access to your protected resources, like your Boldsign account, to third-party applications.
- The Application (aka Client): This is the app that wants to access your protected resources on your behalf. Before the app can request access, it needs to be registered with the authorization server.
- The Data Vault (aka Resource Server): This is where your protected resources, such as your documents are safely stored. The resource server only responds to requests that come with a valid access token.
- The Bouncer (aka Authorization Server): Think of the authorization server as the bouncer at an exclusive club. It authenticates you (the resource owner) and issues access tokens to the application (client) after ensuring proper authorization. It also handles granting and revoking access. BoldSign’s OAuth server takes on this role.
Various flows in OAuth 2.0
OAuth 2.0 framework defines several grant types or “flows” that determine how an application obtains an access token for protected resources. Let’s explore the most common ones:
- Authorization Code Flow: This is the most secure and widely used flow, ideal for server-side web applications. It involves multiple steps to obtain an access token if the user grants permission:
- The application redirects the user to the authorization server.
- The user authenticates and grants permission.
- The authorization server issues an authorization code.
- The application exchanges the authorization code for an access token.
- Client Credentials Flow: This flow is used for machine-to-machine communication where the application acts on its own behalf or on the behalf of a user. The application authenticates directly with the authorization server using its client credentials to obtain an access token to access protected resources.
Selecting the appropriate OAuth 2.0 flow depends on the type of application you’re building and the level of trust between the parties involved. Consider the following guidelines:
- Use the authorization code flow for server-side applications.
- Use the client credentials flow for server-to-server communication.
BoldSign supports both of these flows, allowing you to choose the one that best fits your application’s requirements. We will explore them in detail in the next section.
Acquire BoldSign OAuth Credentials
Before you can start integrating BoldSign OAuth 2.0 into your application, you need to acquire OAuth credentials from BoldSign. If you don’t have a BoldSign account, you can sign up for a free sandbox account here.
Once you are in the BoldSign web app, navigate to the API menu item in the app’s left navigation pane, select OAuth Apps, and click the Create App button in the top-right corner.

Fill in the name and redirect URL of the application. My local web application will run on localhost:3000, so I will use http://localhost:3000/redirect as the redirect URL. Click Save to create the app.

After creation, you will be immediately provided with the client ID and client secret for your application. Copy these details and store them securely, as you will need them to authenticate your application with BoldSign’s OAuth server.

Authorization Code Flow
The authorization code flow is the recommended OAuth 2.0 flow for server-side and mobile applications that need to access BoldSign APIs on behalf of users. PKCE is mandatory when using this flow, adding an extra layer of security to the standard authorization code flow to prevent interception of the authorization code and token exchange.
We are going to build a simple application that will ask the user to log in with their BoldSign account and then display a list of documents from their account. We are going to build this application using Python and Flask.
First, we need a method to generate a PKCE code verifier and challenge. This is a simple Python script that generates a code verifier and its corresponding code challenge for PKCE. The code verifier is a random string, and the code challenge is its SHA256 hash, both encoded in URL-safe Base64 to be sent in the authorization request.
def generate_pkce_pair():
code_verifier = secrets.token_urlsafe(32)
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8')
code_challenge = code_challenge.replace('=', '')
return code_verifier, code_challenge
Install the flask and requests library using pip:
pip install flask requests
Now, let’s create a Python file called app.py and a folder called templates in the same directory. Inside the templates folder, create two files called home.html and documents.html. Your file and folder structure should look like the following.
.
├── app.py
└── templates
├── home.html
└── documents.html
We will see only the important parts of the code in this example, but you can get the entire code example in the GitHub repository here.
Let’s start by defining the Flask app and the home route to return the home page.
app = Flask(__name__)
app.secret_key = secrets.token_hex(16) # Set a secret key for session management
@app.route('/')
def home():
return render_template('home.html')
if __name__ == '__main__':
app.run(debug=True, port=3000)
Login Route and Redirect to BoldSign
Let’s create a login route that will redirect the user to the BoldSign login page. We will use the generate_pkce_pair method to generate the PKCE code verifier and challenge and store it in the session.
Inside the login route, we will construct the authorization URL with the required parameters and redirect the user to the BoldSign login page. In the URL parameters, we specify the response type as code, the client ID, the state, the scope, the redirect URI, the code challenge, and the code challenge method.
The state parameter is a random string generated by the client to protect against cross-site request forgery (CSRF) attacks. The client will validate the state parameter after the user is redirected back from the authorization server to ensure the request originated from the client.
The scope parameter specifies the permissions the client is requesting from the user. In this case, we are requesting the openid, profile, email, offline_access, and BoldSign.Documents.All scopes. The BoldSign.Documents.All scope allows the client to access all documents in the user’s BoldSign account.
The redirect_uri parameter specifies the URL where the authorization server will redirect the user after they grant or deny permission. The redirect URI must match the one registered with the OAuth app in BoldSign. In this case, we have already provided http://localhost:3000/redirect as the redirect URI when creating the OAuth app.
Please note that we have stored the code verifier and state in the session to validate them later when exchanging the authorization code for an access token. The code challenge is sent in the authorization request, and the authorization server will validate it when exchanging the authorization code for an access token.
CLIENT_ID = os.environ.get('CLIENT_ID')
CLIENT_SECRET = os.environ.get('CLIENT_SECRET')
AUTHORIZE_URL = "https://account.boldsign.com/connect/authorize"
TOKEN_URL = "https://account.boldsign.com/connect/token"
DOCUMENT_LIST_URL = "https://api.boldsign.com/v1/document/list"
USER_AGENT = "YourAppName/1.0"
def generate_pkce_pair():
code_verifier = secrets.token_urlsafe(32)
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8')
code_challenge = code_challenge.replace('=', '') # Remove padding
return code_verifier, code_challenge
@app.route('/login')
def login():
code_verifier, code_challenge = generate_pkce_pair()
state = secrets.token_urlsafe(16)
session['code_verifier'] = code_verifier
session['state'] = state
params = {
'response_type': 'code',
'client_id': CLIENT_ID,
'state': state,
'scope': 'openid profile email offline_access BoldSign.Documents.All',
'redirect_uri': url_for('auth_redirect', _external=True),
'code_challenge': code_challenge,
'code_challenge_method': 'S256'
}
authorize_url = f"{AUTHORIZE_URL}?{urllib.parse.urlencode(params)}"
return redirect(authorize_url)
Now, we need a login button in the home.html file that will redirect the user to the login route when clicked.
<a
href="{{ url_for('login') }}"
class="login-button"
>
Login
</a>
When the user clicks the login button, they will be redirected to the BoldSign login page, where they can enter their credentials. After logging in, they will be presented with the user consent screen, where they can see the requested permissions and decide whether to grant access.

After granting permission, the user will be redirected back to the redirect URI specified in the authorization request.
Redirect Handler Route and Token Exchange
In the redirect handler route, we first validate the state parameter to ensure it matches the one stored in the session. If the state parameter does not match, it could indicate a CSRF attack, and we return an error response.
If the state parameter is valid, we extract the authorization code from the query parameters and exchange it for an access token by making a POST request to the token URL. We include the client ID, client secret, authorization code, redirect URI, and code verifier in the request body.
If the token exchange is successful, we store the access token in the session and redirect the user to the documents route. If there is an error during the token exchange, we return an error response with the details.
@app.route('/redirect')
def auth_redirect():
if request.args.get('state') != session.get('state'):
return "State mismatch. Possible CSRF attack.", 400
code = request.args.get('code')
token_response = requests.post(
TOKEN_URL,
data={
'grant_type': 'authorization_code',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'code': code,
'redirect_uri': url_for('auth_redirect', _external=True),
'code_verifier': session.get('code_verifier')
},
headers={
'User-Agent': USER_AGENT
}
)
if token_response.status_code == 200:
token_data = token_response.json()
access_token = token_data.get('access_token')
session['access_token'] = access_token
return redirect(url_for('documents'))
else:
return f"Error exchanging code for token: {token_response.text}", 400
Documents Route
Now that we have obtained the access token, we can use it to make requests to the BoldSign API on behalf of the user.
To keep the example simple, we will fetch and list the documents from the user’s BoldSign account in the documents route. We will make a GET request to the document list URL /v1/document/list and include the access token in the Authorization header with the Bearer scheme.
We also need to create a fetch_documents route that will fetch the documents from the BoldSign API using the access token stored in the session.
@app.route('/documents')
def documents():
return render_template('documents.html')
@app.route('/fetch_documents')
def fetch_documents():
access_token = session.get('access_token')
if not access_token:
return jsonify({"error": "No access token found. Please log in again."}), 401
headers = {
'Authorization': f'Bearer {access_token}',
'User-Agent': USER_AGENT
}
response = requests.get(DOCUMENT_LIST_URL, headers=headers)
if response.status_code == 200:
documents = response.json().get('result', [])
document_titles = [doc.get('messageTitle', 'Untitled') for doc in documents]
return jsonify(document_titles)
else:
return jsonify({"error": f"Failed to fetch documents: {response.text}"}), response.status_code
Next, we need to create a button in the documents.html file that will fetch the documents when clicked.
<h1>Your Documents</h1>
<button id="fetchDocuments">Fetch Documents</button>
<div id="documentList"></div>
<script>
document.getElementById('fetchDocuments').addEventListener('click', function () {
fetch('/fetch_documents')
.then((response) => response.json())
.then((data) => {
// set to html
});
});
</script>
Now, when the user clicks the Fetch Documents button, the documents will be fetched from the BoldSign API and displayed on the page.

Handling Access Token Expiration
Access tokens have a limited lifetime, and they expire after a certain period. When an access token expires, the client needs to obtain a new access token by using the refresh token or by repeating the authorization process.
In this example, we are using the offline_access scope to request a refresh token along with the access token. With the refresh token, the user can obtain a new access token without logging in again.
When the access token expires, we make a POST request to the token URL with the grant_type set to refresh_token and including the refresh token in the request body.
def refresh_token():
refresh_token = session.get("refresh_token")
if not refresh_token:
return None
refresh_response = requests.post(
TOKEN_URL,
data={
"grant_type": "refresh_token",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"refresh_token": refresh_token,
},
headers={"User-Agent": USER_AGENT},
)
if refresh_response.status_code == 200:
token_data = refresh_response.json()
session["access_token"] = token_data.get("access_token")
if "refresh_token" in token_data:
session["refresh_token"] = token_data.get("refresh_token")
else:
# If refresh fails, clear the session and require re-login
session.clear()
return None
You can call the refresh_token method if the token is expired, and the method will attempt to refresh it using the refresh token. If the refresh token is also expired or invalid, the user will need to log in again.
You also have the option to use a sliding expiration for the refresh token. You can enable it in the BoldSign OAuth app settings.

Client Credentials Flow
The client credentials flow is used when the application needs to access resources on its own behalf without user involvement. This flow is typically used for server-to-server communication where the application authenticates directly with the authorization server using its client credentials to obtain an access token.
This flow is most commonly used in internal communications between services or automation tasks that require access to resources without user interaction.
Let’s consider an example where HR management software needs to access the BoldSign API to automatically generate offer letters for new employees. The HR software can use the client credentials flow to obtain an access token to access the BoldSign API on behalf of an HR organization account and send signature requests.
Obtain Access Token Using Client Credentials Flow
In order to use the client credentials flow, you need to have the client ID and client secret of the OAuth app created in BoldSign. We can reuse the CLIENT_ID and CLIENT_SECRET variables from the previous example.
We will create a Python script that demonstrates how to obtain an access token using the client credentials flow and make a request to the BoldSign API to send a signature request using a template.
Here, we have defined the CLIENT_ID, CLIENT_SECRET, TOKEN_URL, and TEMPLATE_SEND_URL variables. The TOKEN_URL is the endpoint where we will request the access token, and the TEMPLATE_SEND_URL is the endpoint to send a signature request using a template. You may notice that the authorization URL is not required in this flow, as the client authenticates directly with the authorization server using its client credentials and does not involve user interaction.
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
TOKEN_URL = "https://account.boldsign.com/connect/token"
TEMPLATE_SEND_URL = "https://api.boldsign.com/v1/template/send"
USER_AGENT = "YourAppName/1.0"
Next, we will define a method called get_access_token that will obtain an access token using the client credentials flow. The method will make a POST request to the token URL with the client ID, client secret, and grant type set to client_credentials.
def get_token():
params = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
}
headers = {"User-Agent": USER_AGENT}
response = requests.post(TOKEN_URL, data=params, headers=headers)
response_data = response.json()
if "error" in response_data:
raise Exception(response_data["error"])
access_token = response_data["access_token"]
return access_token
Send Signature Request Using Template
Now, we will define a method called add_employee that will send a signature request using a template. The method will obtain an access token using the get_access_token method and make a POST request to the template send URL with the access token and template ID.
@app.route("/add_employee")
def add_employee():
access_token = get_access_token()
headers = {"Authorization": f"Bearer {access_token}", "User-Agent": USER_AGENT}
payload = {
"roles": [
{
"roleIndex": 1,
"signerName": "Richard",
"signerEmail": "[email protected]",
}
],
}
url = TEMPLATE_SEND_URL + "?templateId=130cced2-9749-4692-953a-ca623135fefd"
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 201:
return jsonify(response.json())
return jsonify({"error": response.json()}), 400
The template send request contains very minimal data because I have already set up the template with the required fields in the BoldSign web app. The template ID is 130cced2-9749-4692-953a-ca623135fefd, and it is a simple template with a single signer role. You will need to modify the template ID and payload data according to your template structure.
Let’s create a button in the home.html file that will send a signature request when clicked.
<h1>Add employee</h1>
<button
id="send_document"
class="send_document"
>
Add
</button>
<div id="status"></div>
<script>
document.getElementById('send_document').addEventListener('click', function () {
fetch('/add_employee')
.then((response) => response.json())
.then((data) => {
// handle response
})
.catch((error) => {
// handle error
});
});
</script>
When the user clicks the Add button, a signature request will be sent using the template ID specified in the add_employee method. The response will contain the document ID that was created. We display the response like the following.

Conclusion
OAuth 2.0 is a powerful authorization framework that allows applications to access resources on behalf of users or themselves without sharing sensitive information like passwords. BoldSign provides robust support for OAuth 2.0, allowing developers to integrate their applications securely with the BoldSign API. By understanding the key concepts of OAuth 2.0, the roles involved, the flows, and how to use BoldSign OAuth 2.0 in different scenarios, you can build secure and scalable applications that leverage the power of BoldSign’s e-signature capabilities. If you have any questions or need further assistance, feel free to reach out to the BoldSign support team. Happy coding!
