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

Implement authentication flow #22

Open
lancelote opened this issue Jul 31, 2017 · 16 comments
Open

Implement authentication flow #22

lancelote opened this issue Jul 31, 2017 · 16 comments
Assignees

Comments

@lancelote
Copy link
Member

No description provided.

@lourot lourot self-assigned this Dec 29, 2017
@lourot
Copy link
Member

lourot commented Dec 29, 2017

Picking this up as I was trying to implement a new command in which I need to delete a term but I'm getting a 404.

I think I need to look into OAuth as if I understand correctly, I need my user to authorize my API key so that quizler can do more than just listing public sets.

Indeed I also noticed today when playing around that with our current authentication system, quizler can't even list my private sets.

@lourot
Copy link
Member

lourot commented Dec 29, 2017

Which also brings me to another thought: it should be safe for us to create a "client ID" once and for all and hardcode it. No need to ask each user to create their own developer key.

(Read what follows only if you're not familiar with API keys not being secret. I know a lot of great devs who aren't familiar with that stuff, and I also wasn't familiar a couple of years ago, that's why :) )

This should be safe as this is exactly what is done in frontend javascript when accessing an API: these apps don't ask you to go create an API key (= client ID). Instead they have one hardcoded API key which can't be kept secret as it's anyway visible to each client in the javascript. What guarantees that no other app will "steal" our key in that case is:

  1. Why would they? They can create also their own key for free.
  2. This key alone doesn't give access to any private data whatsoever.
  3. The key is tied to a domain which we own, and the browser will anyway redirect to a page of that domain at the end of the OAuth flow. Which makes it impossible for another website to use our key.

3 isn't relevant for us though as we're not running in a browser.

@lancelote
Copy link
Member Author

Yeah, my initial goal was to build a minimum viable project, so I've implemented only the basic Auth which allows read-only access to public data. Anything else requires a more advanced logic, unfortunately.

Hardcoding client ID sounds reasonable but Quizlet explicitly warns to keep it secret: https://quizlet.com/api-dashboard

Do not share your Client ID or Secret Key.

Not sure why though.

@lourot
Copy link
Member

lourot commented Dec 29, 2017

👍 One reason I see meanwhile is that if all our users use the same Client ID, we might hit together API rate limits and disturb each other. Thus we could hardcode a default Client ID and still give an option to use your own instead. But yes, I'll dig more to be really sure that Client IDs shouldn't be secret.

@lancelote
Copy link
Member Author

We can contact Quizlet directly at api@quizlet.com to ask about this (https://quizlet.com/api/2.0/docs/tos). I believe they can indeed set a limitation on specific Client IDs if usage rates are too high.

I quickly searched GitHub for other Python Quizlet API-wrappers and there're some examples of Auth flow implementation, e.g.: https://github.com/hammer/py3quizlet2/blob/master/py3quizlet2.py or https://github.com/tdomhan/pyquizlet/blob/master/pyquizlet.py

@lourot
Copy link
Member

lourot commented Dec 29, 2017

OK I went through the doc, their PHP example, and your python examples. So indeed in my hypothetical case of a frontend (javascript) webapp, the Client ID would be known to any client but the corresponding Secret Key would be kept secret on our backend, which is also involved in the authentication flow.

We are not allowed by Quizlet to hardcode our key pair (Client ID + Secret Key) because we have to keep at least the Secret Key secret.

So either (1) we make our own backend (e.g. quizler.com) and hardcode the Client ID in our python client (quizler CLI), or (2) we need each user to provide their own pair. I vote for (2) for now, as you said, to make an MVP first. (EDIT: implementing (1) one day would make our tool easier to use though)

So I'll create a SECRET_KEY env var, but I'm not sure if the title of this issue means that you don't like env vars?

@lancelote
Copy link
Member Author

I vote for (2) for now, as you said, to make an MVP first. (EDIT: implementing (1) one day would make our tool easier to use though)

I agree, sounds like a reasonable plan 👍

I'm not sure if the title of this issue means that you don't like env vars?

I was thinking about an alternative to env vars initially (config file?) but let's rename this issue as long as it contains the relevant to OAuth comments and you are already working on it.

@lourot lourot changed the title Add additional authentication methods apart of environment variable Implement authentication flow Dec 29, 2017
@lourot
Copy link
Member

lourot commented Dec 30, 2017

Status update: (sorry for all these long messages)

the first part of the auth flow is to GET https://quizlet.com/authorize?response_type=code&client_id=CLIENT_ID&scope=read&state=RANDOM_STRING , but this page requires human intervention (the user may have to log in if not done already, and has to click around). Thus quizler needs to open that page in a browser and wait for the output of the flow, which is a token. Two possibilities:

  1. Ship and use our own in-app browser to avoid the redirection to our backend (which we don't have) and have that special browser communicate the token back to quizler. Unfortunately in-app browsers are forbidden.
  2. Open the page in the user's real browser and set up our own backend. quizler will get the token at the end by polling the backend for it.

It will take me a while to implement but if you're OK with it, let's go for 2. And we will have to hard code our Client ID in quizler and have our Secret Key in the backend (see #22 (comment)) because quizler will work only with our backend which exposes the token back at the end.

So we need an additional github repo for the backend. Do you think we should create a github organization to bundle them?

Also now we are making a CLI that needs browser interaction, which kind of defeats the purpose of a CLI. Maybe we should be doing a webapp or a browser extension instead?

@lancelote
Copy link
Member Author

Also now we are making a CLI that needs browser interaction, which kind of defeats the purpose of a CLI. Maybe we should be doing a web app or a browser extension instead?

Yeap, I was thinking about that also. Maybe we should split the existed code into a pure API-wrapper library hosted at PyPI and a non-CLI tool (or multiple tools including CLI) which uses the library to provide a high-level interface for the users. Or are you thinking about migration to JS altogether? =)

Do you think we should create a github organization to bundle them?

Sounds good to me, do you have any ideas about a name?

  1. Open the page in the user's real browser and set up our own backend. quizler will get the token at the end by polling the backend for it.

That's probably the best way to do it, what stack do you want to use for the backend?

@lourot
Copy link
Member

lourot commented Dec 30, 2017

OK so if we give up on the idea of a CLI with browser-interaction and based on what you said we can:

  • make sure that the current quizler can also be imported as a python lib.
  • create an HTTP server in python that would:
    • import quizler and expose its commands as a trivial REST API (no experience but I guess http.server or Django would be the tools?)
    • act as a backend for the end of the authentication flow
    • deliver the HTML/js frontend

do you have any ideas about a name?

Let me create a quizler organization and make you admin. I'll create some repos there, play around (feel free to ignore them or to look/comment if you're curious), and I'll ping you when I have something worth showing :) No need to move the current quizler repo to the new organization yet. We can first wait and see if this becomes promising.

@lancelote
Copy link
Member Author

no experience but I guess http.server or Django would be the tools?

Django REST framework or Flask-RESTful sound like tools to go. I used to work with Django but have no real experience with REST framework. It should be rather straighforward though - will experiment on my own too.

Let me create a quizler organization

Ok, let's do it 👍

@lourot
Copy link
Member

lourot commented Dec 31, 2017

(there is already a https://github.com/quizler, so I took https://github.com/quizl)

@lourot
Copy link
Member

lourot commented Jan 3, 2018

🎉 I got it working. Bear with me, I'll create a pull request in a few days. I still need to extend the doc, write unit tests and put the backend online to show you :)

@lancelote
Copy link
Member Author

Great! This is a huge work 👍 Btw I transferred quizler to quizl organization.

@lourot
Copy link
Member

lourot commented Jan 4, 2018

Great! We might have to change some paths lancelote/ -> quizl/, basically in the areas related to the 3 badges that we have at the top of the README. We'll see :)

@lancelote
Copy link
Member Author

Oh, yeap, I completely forgot about old links. Not sure if GitHub will preserve correct redirects.

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