Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Unable to create an envelope using DocuSign, API PARTNER_AUTHENTICATION_FAILED #191

Open
ebram96 opened this issue May 23, 2021 · 5 comments

Comments

@ebram96
Copy link

ebram96 commented May 23, 2021

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 = "my@email.com"
        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="my@email.com",
            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-Authentication header 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-Authentication makes it work ??
@LarryKlugerDS
Copy link
Contributor

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 go-live@docusign.com

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!

@ebram96
Copy link
Author

ebram96 commented May 23, 2021

@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!

@LarryKlugerDS
Copy link
Contributor

I'm glad it worked! I agree with your suggestion and will file a bug report against the SDK.

@LarryKlugerDS
Copy link
Contributor

I've filed DCM-5781 and DCM-5782

@ebram96
Copy link
Author

ebram96 commented May 25, 2021

Thanks! Is there a link or something to the filed report ? I can't find it in open issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants