[Proposal] Add token based Auth for API endpoints #285

Open
rigor789 opened this Issue Apr 14, 2016 · 7 comments

Projects

None yet

3 participants

@rigor789

The idea / proposal

I was thinking of exposing API endpoints for spending points. The basic idea is that a trusted webapp can get an API token (issued manually perhaps) and using the token it can request api endpoints to add/remove points from any user.

Why?

The main reason is, that I would like to integrate some features into a website (future anniefuchsia.com) where the logged in users can spend points on some perks.

Access to all users points?

Yes, since the webapp will handle user authentication (via Twitch Oauth2) I can be certain who is spending their points, and reduce their points.

Of course, the token must be kept secret and out of any source control such as git, but if taken care of should not be an issue.

Technical stuff

The tokens could be in the JWT format (JSON Web Token) since that's a pretty standard token implementation nowdays. Also every token would have access scopes for possible future additions.

Possible libraries to handle JWT:

Tokens would not include an expi

Basic Request Flow

Basic Request Flow

How would tokens be issued?

Either through the admin panel, or a simple console command that generates a token with the given scopes for a given user.

Not sure if tokens need to be assigned to a user, opinion welcome

How would API authorization work?

Every request would include the following header

Authorization: Bearer <token>

If the Authorization fails, the following response is returned

{
    "code": "401",
    "message": "Unauthorized",
    "error": "true"
}

If the Authorization is successful, the response would depend on the endpoint.

For example PUT /api/v1/points/ would return

{
    "code": "200",
    "message": "Successfully added {points} points to {user}",
    "error": "false",
    "data": {
        "user": {
            ...
            "points": "{new points}"
            ...
        }
    }
}

Where {user} and {points} are request parameters.

Let's talk about it

Let's discuss any ideas related to this. I'm open to implement this, if you point me in the right direction regarding where to put these things to keep consistent with the rest of the code.

@pajlada
Owner
pajlada commented Apr 15, 2016 edited

I'd be open to this.

As per the library, I'd prefer using flask-jwt for this. I've used it before already and it's worked great.

One of the things I would need to do before this can happen, is to make the user data fully live. Right now there is too much data that is cached in the bot before it's pushed onto the database.

Checklist

  • Make user data fully live between the bot and the website. No cached data in the bot.
      • Decide what columns to keep in MySQL, and what columns to move to redis. The current idea is to move last_seen, last_active, minutes_in_chat_online, minutes_in_chat_offline, points, to redis. But I'm not sure yet.
  • Rework the API and its routes. Right now it uses a mix of flask_restful and just straight up flask routes from a blueprint. Everything should be moved over to flask_restful and split into multiple files.
@rigor789

I guess it needs some cache-busting plus a way to force data from cache to be inserted into db. I guess it should only force update on the users that get changed by the request.

Also about jwt, I guess the standard is to request a token via username + password, but I wouldn't complicate it that much, I would rather have tokens that don't expire issued manually / from admin panel.

Do you think there would be any issues with that?

Main reason I'd like to avoid it, is to not complicate other clients, so they only store a token in an env variable.

@pajlada
Owner
pajlada commented Apr 15, 2016

So authentication-wise you're suggesting there is, for example, an admin page where you can create authentication tokens that can be handed out manually, and revoked manually. With a certain set of permissions. And these tokens don't expire unless manually revoked.

Is it possible to set an infinite expiration date on JWT tokens?

@rigor789

Yeah that's what I was thinking, I believe you can create jwt tokens that don't expire, but an alternative solution is to set the expiration to the far future.

Reading through this answer http://stackoverflow.com/a/26834685 I'm thinking if it's overkill to use jwt instead of regular random strings?

I guess jwt is easier to store access scopes.

@pajlada
Owner
pajlada commented Apr 15, 2016

Using JWT is probably overkill for these "App tokens" then I think. A random string would be preferable. If we were to allow authentication for random users, for them to maybe spend their own points or something then JWT would be more interesting I think.

@rigor789

You are right, let's keep it simple. I don't see any reason for giving out tokens to random users anyways.

@rigor789

Initial token stuff rigor789/pajbot@95b18a4

Basically the constructor of APIToken generates a token with the given scopes, for the given user with the current timestamp.

The token can only be unlocked with the secret_key + the random salt combo.

The unlock_token() will do that, and return the token data like:

{
    'issued_to': '<user_id>',
    'issued_at': '<tmestamp>',
    'scopes': [
        '<all_scopes_of_the_token>',
        '<scope>'
    ]
}
@Nacht123 Nacht123 added the web label Apr 16, 2016
@rigor789 rigor789 referenced this issue Apr 16, 2016
Open

[WIP] Token based authentication as per #285 #286

6 of 7 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment