[Question] Unable to create an envelope using DocuSign, API PARTNER_AUTHENTICATION_FAILED
I'm trying to send an envelope created from a template in my account. But, I'm always getting the response:
HTTP Unauthorized 401
{"errorCode":"PARTNER_AUTHENTICATION_FAILED","message":"The specified Integrator Key was not found or is disabled. An Integrator key was not specified."}
Here is my code:
from docusign_esign import TemplateRole, EnvelopesApi, RecipientViewRequest, EnvelopeDefinition, ApiClient
def create_api_client(base_path, access_token):
"""Create api client and construct API headers"""
api_client = ApiClient()
api_client.host = base_path
api_client.set_default_header(header_name="Authorization", header_value=f"Bearer {access_token}")
return api_client
class Eg001Controller:
@staticmethod
def get_args():
"""Get request and session arguments"""
# More data validation would be a good idea here
# Strip anything other than characters listed
# 1. Parse request arguments
signer_email = "[email protected]"
signer_name = "Some Random Guy"
envelope_args = {
"signer_email": signer_email,
"signer_name": signer_name,
"signer_client_id": "SOME_UNIQUE_VALUE",
"ds_return_url": "http://localhost:5000/ds/callback",
}
args = {
"account_id": {"API_CLIENT_ID"}, # My "API Account ID"
"base_path": "demo.docusign.net/restapi",
"access_token": "{ACCESS_TOKEN_GENERATED_BY_THE_EXAMPLE_CODE_LAUNCHER}",
"envelope_args": envelope_args
}
return args
@classmethod
def worker(cls, args):
"""
1. Create the envelope request object
2. Send the envelope
3. Create the Recipient View request object
4. Obtain the recipient_view_url for the embedded signing
"""
envelope_args = args["envelope_args"]
# 1. Create the envelope request object
envelope_definition = cls.make_envelope(envelope_args)
# 2. call Envelopes::create API method
# Exceptions will be caught by the calling function
print("creating client..")
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
print("creating envelope..")
envelope_api = EnvelopesApi(api_client)
# It fails in the next line!
results = envelope_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition)
envelope_id = results.envelope_id
print(f"Created envelope ID: {envelope_id}")
# 3. Create the Recipient View request object
recipient_view_request = RecipientViewRequest(
authentication_method="None",
client_user_id=envelope_args["signer_client_id"],
recipient_id="1",
return_url=envelope_args["ds_return_url"],
user_name=envelope_args["signer_name"],
email=envelope_args["signer_email"]
)
# 4. Obtain the recipient_view_url for the embedded signing
# Exceptions will be caught by the calling function
results = envelope_api.create_recipient_view(
account_id=args["account_id"],
envelope_id=envelope_id,
recipient_view_request=recipient_view_request
)
return {"envelope_id": envelope_id, "redirect_url": results.url}
@classmethod
def make_envelope(cls, args):
"""
Creates envelope
args -- parameters for the envelope:
signer_email, signer_name, signer_client_id
returns an envelope definition
"""
print("creating envelope definition..")
# Create the envelope definition
envelope_definition = EnvelopeDefinition(
status="sent", # requests that the envelope be created and sent.
template_id="{TEMPLATE_ID}"
)
# Create template role elements to connect the signer and cc recipients
# to the template
signer = TemplateRole(
email="[email protected]",
name="Some Random Guy",
role_name='Signer',
client_user_id="SOME_UNIQUE_VALUE"
)
# Add the TemplateRole objects to the envelope object
envelope_definition.template_roles = [signer]
return envelope_definition
Eg001Controller.worker(Eg001Controller.get_args())
Most of the code is duplicated from this example.
Notes:
- I thought there might be a problem in generating the access token, so, I used the same token generated when I run their code launcher. There shouldn't be any problem with the token.
- I also get the same response if I generate the token manually with this code: (I'm using JWT auth)
def jwt_auth():
"""JSON Web Token authorization"""
api_client = ApiClient()
api_client.set_base_path(BASE_PATH)
# try:
ds_app = api_client.request_jwt_user_token(
client_id=INTEGRATION_KEY,
user_id=USER_ID,
oauth_host_name=AUTH_SERVER,
private_key_bytes=PRIVATE_KEY.encode("ascii").decode("utf-8"),
expires_in=3600, # Not configurable/extensible.
scopes=SCOPES
)
return ds_app
- Their code launcher is able to complete embedded signing successfully with my account!
- When I add
X-DocuSign-Authenticationheader that contains my account username & password, it works. But, certainly I want to be able to use just the token, not my login credentials! - Why adding
X-DocuSign-Authenticationmakes it work ??
Hi, See https://www.docusign.com/blog/dsdev-from-the-trenches-may-2020 for some ideas.
From a quick look, I think your base_path should be set to https://demo.docusign.net/restapi
(The JWT claim for the oauth service provider is just the domain name, but the base_path includes the full URL.)
If the above doesn't work, please open a developer support case via [email protected]
Re: it works if you use the X-DocuSign-Authentication header
Yes, that's "legacy authentication" which is no longer supported for new apps. Please use OAuth instead, as you're doing. You're close!
@LarryKlugerDS Dear lord! It worked after adding the 'https' to the base URL! Some validation should have been added to the SDK to validate that part! I've been bashing my head to the wall. Thank you! But, the error message is really misleading! I thought it's something about authentication!
I'm glad it worked! I agree with your suggestion and will file a bug report against the SDK.
I've filed DCM-5781 and DCM-5782
Thanks! Is there a link or something to the filed report ? I can't find it in open issues.