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

In the Node.js example what is the correct way to prevent having to authenticate via an url every script restart? #143

Open
vjpr opened this issue Aug 8, 2017 · 2 comments
Assignees

Comments

@vjpr
Copy link

vjpr commented Aug 8, 2017

What is the correct way to obtain the access_token in a NativeFlow auth?

You follow an url and get a code. Then you are asked to type the code into a prompt. But then how can I get the accessToken (I am assuming that somewhere client.app.accessTokenFromCode is being run - but where are the credentials?).

@vjpr
Copy link
Author

vjpr commented Aug 8, 2017

So seems like I can get it via:

const res = await client.authorize()
console.log(res.dispatcher.authenticator)
OauthAuthenticator {
  credentials:
    ...

Is this correct?


Also, calling await client.authorize() with a valid access_token always causes a prompt to show when in NativeFlow flow.

@praecipula
Copy link
Contributor

praecipula commented Aug 9, 2017

I think I follow what you're asking here, let me try to send you along the right path!

When you go through the oauth flow, basically the idea is that there are 3 actors: the user, your app, and Asana. The flow you're likely looking for is here.

  1. You send the user to a URL that Asana owns; that is, your goal is to get the user to visit a particular url. For Asana, this is https://app.asana.com/-/oauth_authorize. (Note that we respond with an error if you don't sent a correct client_id param). Note that client_secret is not sent at this point, only client_id and redirect_uri

  2. If they agree to give access (the user-in-the-loop part), assuming that you supply a redirect url, Asana sends back a redirect request to the user's browser with a short-lived code. If you used the "out-of-band" redirect of URI (urn:ietf:wg:oauth:2.0:oob), the user will have to copy-paste this code into your app (or some other way of supplying it). This code is short-lived and so isn't useful to persist

  3. You send this code from your app as a POST request to https://app.asana.com/-/oauth_token with your client_secret to Asana. This is where your application actually asks for credentials; the token given in the previous phases simply acknowledges that for a short time, the user has given your app permission to ask for these credentials, and your client_secret assures Asana that, for this server-side request, your app really is yours (it's like your application's password).

  4. We send back an access_token which represents (approximately) a client-user credential pair that is valid for an hour, so may or may not be useful to persist, depending on how you run your script. This is the credential actually used to access our API on behalf of this user.
    We also send back a refresh_token which is long-lived, and you should persist it if you want to save users from going through the authorization step every time. It's used to get new short-lived access_tokens after they expire in a very similar way to exchanging the original code.

So, basically, you actually use the access_token to access Asana. You can either get this from the code that you exchange just after the user gives you access or from the refresh_token for a long time after that initial code exchange. The refresh_token is the correct long-lived token that represents a user-app authorization pair.

When you do the token exchange, take a look at the credentials that come back (just as you logged to console is fine) - I believe you should have the refresh_token there. If you save that somewhere secure, then you can construct your client with this token in its credentials in the future I think (though I haven't tested it) just constructing the client in this way will handle future refreshes without requiring you to call client.authorize()

If you look at the useOauth() function, you can see that it takes some options. If you pass it credentials, you should be able to keep using the ones you have stored. I believe all you have to do then is pass in the credential for access_token (if it's been less than an hour) or refresh_token (if greater than an hour) and our client library should know how to proceed from there. (I believe you can pass it both, and it will automatically refresh if the client token is expired).

Hopefully this gets you unblocked - we should perhaps show more than just the original code exchange in our examples to show starting from scratch with a saved refresh token. OAuth is messy and kind of hard, so I hope this makes a bit more sense!

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

No branches or pull requests

2 participants