GearPlug/dynamics365crm-python

Unclear usage

duoi opened this issue · 7 comments

duoi commented

I don't understand how you go from get authorization url to getting a code that can be passed to exchange_code. Can this be clarified?

@duoi I'm having the same issue. Were you ever able to figure it out?

duoi commented

@pcooperKAC the answer is "yes" in quotation marks.

I didn't end up using the approach in the documentation. I was already using adal (here) so I ended up deciding to authenticate with that and just using this package as an API to interact with dynamics, rather than having this package deal with the authentication as well.

Something like this is what I ended up with:

import adal
from msrestazure.azure_active_directory import AADTokenCredentials
from dynamics365crm.client import Client


class Dynamics365Client():
    def __init__(self):
        super().__init__()

        self.resource_uri = DYNAMICS__RESOURCE_URI
        self.client_id = DYNAMICS__CLIENT_ID
        self.client_secret = DYNAMICS__CLIENT_SECRET
        self.tenant = DYNAMICS__TENANT

        self.client = self.authenticate()

    def _authenticate_client_key(self):
        authority_uri = 'https://login.microsoftonline.com/{tenant}'.format(
            tenant=self.tenant
        )
        context = adal.AuthenticationContext(
            authority=authority_uri,
            api_version=None
        )
        mgmt_token = context.acquire_token_with_client_credentials(
            resource=self.resource_uri,
            client_id=self.client_id,
            client_secret=self.client_secret
        )
        credentials = AADTokenCredentials(
            token=mgmt_token,
            client_id=self.client_id
        )

        return credentials

    def authenticate(self):
        self.client = Client(
            resource=self.resource_uri,
            client_id=self.client_id,
            client_secret=self.client_secret
        )
        self.client.set_token(
            token=self._authenticate_client_key().token.get('access_token')
        )

        return self.client

Hello there, sorry for the delay.

The process is called OAuth 2.0 authorization code flow. Basically, you construct an authorization url using the url_petition method. The user access to this url and authorize your app with a set of permissions (scopes). The user is redirected to your web server and you grab the authorization code and exchange it with the exchange_code method for an access token. Then you start using the provided access token to access resources on the user behalf.

I hope this help you to understand the flow.

If you need more information, let me know.

duoi commented

@ingmferrer right, the confusion seems to be around the purpose of the package.

For my usage, I was automatically adding customers to Dynamics365 after their registration. Which is why my approach was the way it was.

I guess the intention of this package is to just provide a separate interface for a human user of the CRM to interact with Dynamics?

Hello @duoi and @pcooperKAC

It seems you guys haven't had much intereaction with the OAuth authentication methods, so I'll try to explain how it works.

What is OAuth 2.0? To put it simple, it's a way to obtain user permissions to access something in their account. The access is limited to the service you are using, in this case Dynamics365 and to whatever the user gave you access to. A clear example of this is any application that asks you to link with Facebook, it will prompt a screen for you to give access for them to some items in your facebook account.

Now that you know what OAuth is lets see how can you go through this with the library.
First do this:

c = Client(**my _kwargs)
authorization_url = c.url_petition(redirect_uri='https://goto.mypage.com/oauth/dynamics365/callback')

Now you have the authorization_url and you can use it to ask any user permissions over their dynamics365 account. You can try and open it yourself and it should ask you to grant permissions.

Anytime someone gives you permissions you should get a request to the url you specified in the redirect_uri. In my case it was https://goto.mypage.com/oauth/dynamics365/callback.

That request should contain a code, usually via get paramenters, so the url should actually look like this: https://goto.mypage.com/oauth/dynamics365/callback?code=thisismycode12. Now you should get the code from that url in your application backend and call the next method:

c = Client(**my _kwargs)
code = 'thisismycode12'  # Get this from the url parameters
finally_my_token = c.exchange_code('https://goto.mypage.com/oauth/dynamics365/callback', code)

Now you have the token you need to use the library as the person who gave you access, but you can only do whatever the user authorized you to do.

I hope that helped.

@duoi I was able to get what I needed with the code that you pasted. Many thanks!

duoi commented

@gustav0 I'm familiar with Oauth, I just didn't feel this was necessary:

Now you have the authorization_url and you can use it to ask any user permissions over their dynamics365 account. You can try and open it yourself and it should ask you to grant permissions.

My approach doesn't require any users to interact at any stage. You authorize it from Azure and get going indefinitely, re-authenticating for each instantiation (so I don't even need to worry about renewing tokens).