From 86ec831ebaafaeab3f7612f149c2db414abeb3f9 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Wed, 16 Jun 2021 14:17:20 -0400 Subject: [PATCH] Create login resource --- src/webqueue2api/api/resources/__init__.py | 1 + src/webqueue2api/api/resources/login.py | 51 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/webqueue2api/api/resources/login.py diff --git a/src/webqueue2api/api/resources/__init__.py b/src/webqueue2api/api/resources/__init__.py index e69de29..751474d 100644 --- a/src/webqueue2api/api/resources/__init__.py +++ b/src/webqueue2api/api/resources/__init__.py @@ -0,0 +1 @@ +from .login import Login \ No newline at end of file diff --git a/src/webqueue2api/api/resources/login.py b/src/webqueue2api/api/resources/login.py new file mode 100644 index 0000000..29430f8 --- /dev/null +++ b/src/webqueue2api/api/resources/login.py @@ -0,0 +1,51 @@ +from flask import request, after_this_request +from flask_restful import Resource +from flask_jwt_extended import create_access_token, create_refresh_token, set_refresh_cookies +from ..auth import user_is_valid + + + +class Login(Resource): + def post(self) -> tuple: + """Validates username/password, sets refresh token cookie and returns access token. + + Return Codes: + 200 (OK): On success. + 401 (Unauthroized): When username or password are incorrect. + 422 (Unprocessable Entitiy): When the username or password can't be parsed. + + Example: + curl -X POST + -H "Content-Type: application/json" + -d '{"username": "bob", "password": "super_secret"}' + + { "access_token": fjr09hfp09h932jp9ruj3.3r8ihf8h0w8hr08ifhj804h8i.8h48ith08ity409hip0t4 } + + Returns: + tuple: Response containing tokens and HTTP response code. + """ + if not request.is_json: + return ({ "message": "JSON missing from request body"}, 422) + + data = request.json + + fields_to_check = ["username", "password"] + for field in fields_to_check: + if field not in data.keys(): + return ({ "message": f"{field} missing from request body"}, 422) + + if not user_is_valid(data["username"], data["password"]): + return ({ "message": "Username or password is invalid"}, 401) + + access_token = create_access_token(data["username"]) + refresh_token = create_refresh_token(data["username"]) + + # This decorator is needed because Flask-RESTful's 'resourceful routing` + # doesn't allow for direct modification to the Flask response object. + # See: https://flask-restful.readthedocs.io/en/latest/quickstart.html#resourceful-routing + @after_this_request + def set_refresh_cookie_callback(response): + set_refresh_cookies(response, refresh_token) + return response + + return ({ "access_token": access_token }, 200) \ No newline at end of file