Python flask.request.content_type() Examples

The following are 27 code examples of flask.request.content_type(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module flask.request , or try the search function .
Example #1
Source File: getpostdata.py    From SSRSpeed with GNU General Public License v3.0 12 votes vote down vote up
def getPostData():
	#print(request.content_type)
	data = {}
	if (request.content_type.startswith('application/json')):
		data = request.get_data()
		return json.loads(data.decode("utf-8"))
	elif(request.content_type.startswith("application/x-www-form-urlencoded")):
		#print(1)
		#print(urllib.parse.parse_qs(request.get_data().decode("utf-8")))
		return parse_qs_plus(urllib.parse.parse_qs(request.get_data().decode("utf-8")))
	else:
		for key, value in request.form.items():
			if key.endswith('[]'):
				data[key[:-2]] = request.form.getlist(key)
			else:
				data[key] = value
		return data 
Example #2
Source File: bento_api_server.py    From BentoML with Apache License 2.0 6 votes vote down vote up
def feedback_view_func(bento_service):
        """
        User send feedback along with the request Id. It will be stored and
        ready for further process.
        """
        if request.content_type != "application/json":
            return Response(
                response="Incorrect content format, require JSON", status=400
            )

        data = json.loads(request.get_data().decode("utf-8"))

        if "request_id" not in data.keys():
            return Response(response="Missing request id", status=400)

        if len(data.keys()) <= 1:
            return Response(response="Missing feedback data", status=400)

        data["service_name"] = bento_service.name
        data["service_version"] = bento_service.version

        feedback_logger.info(data)
        return Response(response="success", status=200) 
Example #3
Source File: utils.py    From ansible-runner-service with Apache License 2.0 5 votes vote down vote up
def log_request(logger):
    '''
    wrapper function for HTTP request logging
    '''
    def real_decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            """ Look at the request, and log the details """
            # logger.info("{}".format(request.url))
            logger.debug("Request received, content-type :"
                         "{}".format(request.content_type))
            if request.content_type == 'application/json':
                sfx = ", parms={}".format(request.get_json())
            else:
                sfx = ''
            logger.info("{} - {} {}{}".format(request.remote_addr,
                                              request.method,
                                              request.path,
                                              sfx))
            return f(*args, **kwargs)
        return wrapper

    return real_decorator 
Example #4
Source File: app.py    From python-examples with MIT License 5 votes vote down vote up
def file():
    print(request.args)
    print(request.data)
    print(request.files)
    print(request.headers)
    
    file_ = request.files.get('file')

    if file_:
        #file_.save('output.pdf')
        data = file_.read()
        print(len(data))
        print(data[:20])
        return jsonify({
            'msg': 'success',
            'request.content_type': request.content_type,
            'request.content_length': request.content_length,
            'filename': file_.filename,
            'len': len(data),
            'first': data[:20].decode('unicode_escape'), # convert bytes to string which can be send in JSON
        })
    else:
        return jsonify({
            'msg': 'no file',
            'request.content_type': request.content_type,
        }) 
Example #5
Source File: app.py    From python-examples with MIT License 5 votes vote down vote up
def create_binary():
    print(request.args)
    print(request.data)
    print(request.files)
    print(request.headers)
    
    if request.content_type == "application/octet-stream":
        data = request.get_data()
        print(len(data))
        print(data[:20])
        return jsonify({
            'msg': 'success',
            'request.content_type': request.content_type,
            'request.content_length': request.content_length,
            'len': len(data),
            'first': data[:20].decode('unicode_escape'), # convert bytes to string which can be send in JSON
        })
    else:
        return jsonify({
            'msg': '415 Unsupported Media Type ;)',
            'request.content_type': request.content_type,
        }) 
Example #6
Source File: __init__.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def get_current_user():
    if authed():
        user = Users.query.filter_by(id=session["id"]).first()

        # Check if the session is still valid
        session_hash = session.get("hash")
        if session_hash:
            if session_hash != hmac(user.password):
                logout_user()
                if request.content_type == "application/json":
                    error = 401
                else:
                    error = redirect(url_for("auth.login", next=request.full_path))
                abort(error)

        return user
    else:
        return None 
Example #7
Source File: visibility.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def check_account_visibility(f):
    @functools.wraps(f)
    def _check_account_visibility(*args, **kwargs):
        v = get_config(ConfigTypes.ACCOUNT_VISIBILITY)
        if v == AccountVisibilityTypes.PUBLIC:
            return f(*args, **kwargs)

        elif v == AccountVisibilityTypes.PRIVATE:
            if authed():
                return f(*args, **kwargs)
            else:
                if request.content_type == "application/json":
                    abort(403)
                else:
                    return redirect(url_for("auth.login", next=request.full_path))

        elif v == AccountVisibilityTypes.ADMINS:
            if is_admin():
                return f(*args, **kwargs)
            else:
                abort(404)

    return _check_account_visibility 
Example #8
Source File: visibility.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def check_score_visibility(f):
    @functools.wraps(f)
    def _check_score_visibility(*args, **kwargs):
        v = get_config(ConfigTypes.SCORE_VISIBILITY)
        if v == ScoreVisibilityTypes.PUBLIC:
            return f(*args, **kwargs)

        elif v == ScoreVisibilityTypes.PRIVATE:
            if authed():
                return f(*args, **kwargs)
            else:
                if request.content_type == "application/json":
                    abort(403)
                else:
                    return redirect(url_for("auth.login", next=request.full_path))

        elif v == ScoreVisibilityTypes.HIDDEN:
            return (
                render_template("errors/403.html", error="Scores are currently hidden"),
                403,
            )

        elif v == ScoreVisibilityTypes.ADMINS:
            if is_admin():
                return f(*args, **kwargs)
            else:
                abort(404)

    return _check_score_visibility 
Example #9
Source File: __init__.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def require_team(f):
    @functools.wraps(f)
    def require_team_wrapper(*args, **kwargs):
        if get_config("user_mode") == TEAMS_MODE:
            team = get_current_team()
            if team is None:
                if request.content_type == "application/json":
                    abort(403)
                else:
                    return redirect(url_for("teams.private", next=request.full_path))
        return f(*args, **kwargs)

    return require_team_wrapper 
Example #10
Source File: __init__.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def admins_only(f):
    """
    Decorator that requires the user to be authenticated and an admin
    :param f:
    :return:
    """

    @functools.wraps(f)
    def admins_only_wrapper(*args, **kwargs):
        if is_admin():
            return f(*args, **kwargs)
        else:
            if request.content_type == "application/json":
                abort(403)
            else:
                return redirect(url_for("auth.login", next=request.full_path))

    return admins_only_wrapper 
Example #11
Source File: __init__.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def authed_only(f):
    """
    Decorator that requires the user to be authenticated
    :param f:
    :return:
    """

    @functools.wraps(f)
    def authed_only_wrapper(*args, **kwargs):
        if authed():
            return f(*args, **kwargs)
        else:
            if (
                request.content_type == "application/json"
                or request.accept_mimetypes.best == "text/event-stream"
            ):
                abort(403)
            else:
                return redirect(url_for("auth.login", next=request.full_path))

    return authed_only_wrapper 
Example #12
Source File: __init__.py    From CTFd with Apache License 2.0 5 votes vote down vote up
def require_verified_emails(f):
    """
    Decorator to restrict an endpoint to users with confirmed active email addresses
    :param f:
    :return:
    """

    @functools.wraps(f)
    def _require_verified_emails(*args, **kwargs):
        if get_config("verify_emails"):
            if current_user.authed():
                if (
                    current_user.is_admin() is False
                    and current_user.is_verified() is False
                ):  # User is not confirmed
                    if request.content_type == "application/json":
                        abort(403)
                    else:
                        return redirect(url_for("auth.confirm"))
        return f(*args, **kwargs)

    return _require_verified_emails 
Example #13
Source File: handler.py    From transmute-core with MIT License 5 votes vote down vote up
def create_routes_and_handler(transmute_func, context):

    @wraps(transmute_func.raw_func)
    def handler(*args, **kwargs):
        exc, result = None, None
        try:
            args, kwargs = _param_instance.extract_params(
                context, transmute_func, request.content_type,
            )
            result = transmute_func(*args, **kwargs)
        except Exception as e:
            exc = e
            exc.__traceback__ = sys.exc_info()[2]
        response = transmute_func.process_result(
            context, result, exc, request.content_type
        )
        return Response(
            response["body"],
            status=response["code"],
            mimetype=response["content-type"],
            headers=response["headers"],
        )
    return (
        _convert_paths_to_flask(transmute_func.paths),
        handler
    ) 
Example #14
Source File: example.py    From transmute-core with MIT License 5 votes vote down vote up
def add_swagger(app, json_route, html_route, **kwargs):
    """
    add a swagger html page, and a swagger.json generated
    from the routes added to the app.
    """
    spec = getattr(app, SWAGGER_ATTR_NAME)
    if spec:
        spec = spec.swagger_definition(**kwargs)
    else:
        spec = {}
    encoded_spec = json.dumps(spec).encode("UTF-8")

    @app.route(json_route)
    def swagger():
        return Response(
            encoded_spec,
            # we allow CORS, so this can be requested at swagger.io
            headers={"Access-Control-Allow-Origin": "*"},
            content_type="application/json",
        )

    # add the statics
    static_root = get_swagger_static_root()
    swagger_body = generate_swagger_html(
        STATIC_PATH, json_route
    ).encode("utf-8")

    @app.route(html_route)
    def swagger_ui():
        return Response(swagger_body, content_type="text/html")

    # the blueprint work is the easiest way to integrate a static
    # directory into flask.
    blueprint = Blueprint('swagger', __name__, static_url_path=STATIC_PATH,
                          static_folder=static_root)
    app.register_blueprint(blueprint)

# example usage. 
Example #15
Source File: example.py    From transmute-core with MIT License 5 votes vote down vote up
def create_routes_and_handler(transmute_func, context):
    """
    return back a handler that is the api generated
    from the transmute_func, and a list of routes
    it should be mounted to.
    """
    @wraps(transmute_func.raw_func)
    def handler():
        exc, result = None, None
        try:
            args, kwargs = ParamExtractorFlask().extract_params(
                context, transmute_func, request.content_type
            )
            result = transmute_func(*args, **kwargs)
        except Exception as e:
            exc = e
            """
            attaching the traceack is done for you in Python 3, but
            in Python 2 the __traceback__ must be
            attached to the object manually.
            """
            exc.__traceback__ = sys.exc_info()[2]
        """
        transmute_func.process_result handles converting
        the response from the function into the response body,
        the status code that should be returned, and the
        response content-type.
        """
        response = transmute_func.process_result(
            context, result, exc, request.content_type
        )
        return Response(
            response["body"],
            status=response["code"],
            mimetype=response["content-type"],
            headers=response["headers"]
        )
    return (
        _convert_paths_to_flask(transmute_func.paths),
        handler
    ) 
Example #16
Source File: manifest.py    From quay with Apache License 2.0 5 votes vote down vote up
def _parse_manifest():
    content_type = request.content_type or DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE
    if content_type == "application/json":
        # For back-compat.
        content_type = DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE

    try:
        return parse_manifest_from_bytes(Bytes.for_string_or_unicode(request.data), content_type)
    except ManifestException as me:
        logger.exception("failed to parse manifest when writing by tagname")
        raise ManifestInvalid(detail={"message": "failed to parse manifest: %s" % me}) 
Example #17
Source File: manifest.py    From quay with Apache License 2.0 5 votes vote down vote up
def _reject_manifest2_schema2(func):
    @wraps(func)
    def wrapped(*args, **kwargs):
        namespace_name = kwargs["namespace_name"]
        if (
            request.content_type
            and request.content_type != "application/json"
            and request.content_type
            not in DOCKER_SCHEMA1_CONTENT_TYPES | DOCKER_SCHEMA2_CONTENT_TYPES | OCI_CONTENT_TYPES
        ):
            raise ManifestInvalid(
                detail={"message": "manifest schema version not supported"}, http_status_code=415
            )

        if namespace_name not in app.config.get("V22_NAMESPACE_BLACKLIST", []):
            if request.content_type in OCI_CONTENT_TYPES:
                if (
                    namespace_name not in app.config.get("OCI_NAMESPACE_WHITELIST", [])
                    and not features.GENERAL_OCI_SUPPORT
                ):
                    raise ManifestInvalid(
                        detail={"message": "manifest schema version not supported"},
                        http_status_code=415,
                    )

            return func(*args, **kwargs)

        if (
            _doesnt_accept_schema_v1()
            or request.content_type in DOCKER_SCHEMA2_CONTENT_TYPES | OCI_CONTENT_TYPES
        ):
            raise ManifestInvalid(
                detail={"message": "manifest schema version not supported"}, http_status_code=415
            )
        return func(*args, **kwargs)

    return wrapped 
Example #18
Source File: bento_api_server.py    From BentoML with Apache License 2.0 5 votes vote down vote up
def log_image(req, request_id):
        if not config('logging').getboolean('log_request_image_files'):
            return []

        img_prefix = 'image/'
        log_folder = config('logging').get('base_log_dir')

        all_paths = []

        if req.content_type and req.content_type.startswith(img_prefix):
            filename = '{timestamp}-{request_id}.{ext}'.format(
                timestamp=int(time.time()),
                request_id=request_id,
                ext=req.content_type[len(img_prefix) :],
            )
            path = os.path.join(log_folder, filename)
            all_paths.append(path)
            with open(path, 'wb') as f:
                f.write(req.get_data())

        for name in req.files:
            file = req.files[name]
            if file and file.filename:
                orig_filename = secure_filename(file.filename)
                filename = '{timestamp}-{request_id}-{orig_filename}'.format(
                    timestamp=int(time.time()),
                    request_id=request_id,
                    orig_filename=orig_filename,
                )
                path = os.path.join(log_folder, filename)
                all_paths.append(path)
                file.save(path)
                file.stream.seek(0)

        return all_paths 
Example #19
Source File: bento_api_server.py    From BentoML with Apache License 2.0 5 votes vote down vote up
def _request_to_json(req):
    """
    Return request data for log prediction
    """
    if req.content_type == "application/json":
        return req.get_json()

    return {} 
Example #20
Source File: server.py    From ebonite with Apache License 2.0 5 votes vote down vote up
def create_executor_function(interface: Interface, method: str):
    """
    Creates a view function for specific interface method

    :param interface: :class:`.Interface` instance
    :param method: method name
    :return: callable view function
    """
    from flask import g, jsonify, request, send_file

    def ef():
        try:
            if request.content_type == 'application/json':
                request_data = BaseHTTPServer._deserialize_json(interface, method, request.json)
            else:
                request_data = dict(itertools.chain(request.form.items(), request.files.items()))

            result = BaseHTTPServer._execute_method(interface, method, request_data, g.ebonite_id)

            if isinstance(result, bytes):
                return send_file(BytesIO(result), mimetype='image/png')
            return jsonify(result)
        except MalformedHTTPRequestException as e:
            return jsonify(e.response_body()), e.code()

    ef.__name__ = method

    return ef 
Example #21
Source File: scan.py    From plex_autoscan with GNU General Public License v3.0 5 votes vote down vote up
def api_call():
    data = {}
    try:
        if request.content_type == 'application/json':
            data = request.get_json(silent=True)
        elif request.method == 'POST':
            data = request.form.to_dict()
        else:
            data = request.args.to_dict()

        # verify cmd was supplied
        if 'cmd' not in data:
            logger.error("Unknown %s API call from %r", request.method, request.remote_addr)
            return jsonify({'error': 'No cmd parameter was supplied'})
        else:
            logger.info("Client %s API call from %r, type: %s", request.method, request.remote_addr, data['cmd'])

        # process cmds
        cmd = data['cmd'].lower()
        if cmd == 'queue_count':
            # queue count
            if not conf.configs['SERVER_USE_SQLITE']:
                # return error if SQLITE db is not enabled
                return jsonify({'error': 'SERVER_USE_SQLITE must be enabled'})
            return jsonify({'queue_count': db.get_queue_count()})

        else:
            # unknown cmd
            return jsonify({'error': 'Unknown cmd: %s' % cmd})

    except Exception:
        logger.exception("Exception parsing %s API call from %r: ", request.method, request.remote_addr)

    return jsonify({'error': 'Unexpected error occurred, check logs...'}) 
Example #22
Source File: rest_utils.py    From cloudify-manager with Apache License 2.0 5 votes vote down vote up
def get_json_and_verify_params(params=None):
    params = params or []
    if request.content_type != 'application/json':
        raise manager_exceptions.UnsupportedContentTypeError(
            'Content type must be application/json')

    request_dict = request.json
    is_params_dict = isinstance(params, dict)

    def is_optional(param_name):
        return is_params_dict and params[param_name].get('optional', False)

    def check_type(param_name):
        return is_params_dict and params[param_name].get('type', None)

    for param in params:
        if param not in request_dict:
            if is_optional(param):
                continue
            raise manager_exceptions.BadParametersError(
                'Missing {0} in json request body'.format(param))

        param_type = check_type(param)
        if param_type and not isinstance(request_dict[param], param_type):
            raise manager_exceptions.BadParametersError(
                '{0} parameter is expected to be of type {1} but is of type '
                '{2}'.format(param,
                             param_type.__name__,
                             type(request_dict[param]).__name__))
    return request_dict 
Example #23
Source File: view_decorators.py    From flask-jwt-extended with MIT License 5 votes vote down vote up
def _decode_jwt_from_json(request_type):
    if request.content_type != 'application/json':
        raise NoAuthorizationError('Invalid content-type. Must be application/json.')

    if request_type == 'access':
        token_key = config.json_key
    else:
        token_key = config.refresh_json_key

    try:
        encoded_token = request.json.get(token_key, None)
        if not encoded_token:
            raise BadRequest()
    except BadRequest:
        raise NoAuthorizationError('Missing "{}" key in json data.'.format(token_key))

    return encoded_token, None 
Example #24
Source File: http_server.py    From ns4_chatbot with Apache License 2.0 4 votes vote down vote up
def _process_web_request(self,flag,func=None):
        data = None
        s_json = None
        if request.content_type is None:#get请求
            data = request.args
        else:#类型为: application/x-www-form-urlencoded
            s_json = request.get_data()
            if s_json is None or s_json == '':
                logger.warn(u"json数据为空")

            else:
                if flag!="coolq_callback":#QQ的回调接口,任何消息都回调,所以不能记录他们
                    logger.debug("接收到来自网络的数据:%s",s_json)

                try:
                    #2018.10.16 bug,文本中有tab\return 旧会导致json解析失败,替换掉
                    s_json = s_json.replace("\t", "").replace("\n", "")
                    # data = json.loads(s_json.decode('ISO-8859-1'))#.decode('ISO-8859-1')
                    data = json.loads(s_json)

                except ValueError as ve:
                    logger.exception(ve,"无法解析json数据:%s",s_json)
                    return "Error Parse Json: error("+str(ve)+"),json="+s_json,500

        #处理coolq的回调消息,这个是本机上的酷Q-docker接收到消息,回调我们的            
        if flag == "coolq_callback":
            rmsg = self.qqbot.on_message(data) 
            if rmsg:
                return jsonify({"reply":rmsg})#必须是json格式,文档里说文本即可,不行
            else:
                return "",204#大部分消息不需要处理,直接忽略<https://cqhttp.cc/docs/4.7/#/Post?id=%E4%B8%8A%E6%8A%A5%E8%AF%B7%E6%B1%82%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F>

        bizComponent = self.bizManager.load_biz_comp(flag)

        if bizComponent is None:
            logger.error("无法找到业务组件来为此HTTP请求服务,flag=%s",flag)
            return "系统错误:无法找到内部业务组件给您服务", 500
        else:
            logger.debug("加载业务处理器:%r",bizComponent)

        try:
            result = bizComponent.system2bot(data,func)
        except Exception as ve:
            logger.exception(ve,"业务处理组件发生错误data=[%s],func=[%s]",s_json,func)
            return "Error Happen Inside Business Component:"+str(ve),500
        if result=="OK":
            return "OK",200
        else:
            return result, 500 
Example #25
Source File: job_artifacts.py    From zeus with Apache License 2.0 4 votes vote down vote up
def handle_async(self, hook, build_xid, job_xid):
        if request.content_type == "application/json":
            # file must be base64 encoded
            file_data = request.json.get("file")
            if not file_data:
                return self.respond({"file": "Missing file content."}, status=403)

            file = FileStorage(BytesIO(b64decode(file_data)), request.json.get("name"))
        else:
            try:
                file = request.files["file"]
            except KeyError:
                return self.respond(
                    {"file": "Missing data for required field."}, status=403
                )

        artifact = self.schema_from_request(pending_artifact_schema)
        artifact.external_build_id = build_xid
        artifact.external_job_id = job_xid
        artifact.provider = hook.provider
        artifact.repository_id = hook.repository_id
        artifact.status = Status.queued
        artifact.hook_id = hook.id

        if not artifact.name:
            artifact.name = file.filename

        if not artifact.name:
            return self.respond(
                {"name": "Missing data for required field."}, status=403
            )

        try:
            db.session.add(artifact)
            db.session.flush()
        except IntegrityError:
            db.session.rollback()
            exists = True
        else:
            exists = False

        if exists:
            # XXX(dcramer): this is more of an error but we make an assumption
            # that this happens because it was already sent
            return self.error("An artifact with this name already exists", 204)

        artifact.file.save(
            file,
            "{0}/{1}/{2}_{3}".format(
                job_xid[:4], job_xid[4:], artifact.id.hex, artifact.name
            ),
        )
        db.session.add(artifact)
        db.session.commit()

        return self.respond_with_schema(pending_artifact_schema, artifact, 202) 
Example #26
Source File: __init__.py    From build-relengapi with Mozilla Public License 2.0 4 votes vote down vote up
def _insert_many(project, ignore_dups=False):
    """Update the database with many git-hg mappings.

    Args:
        project: Single project name string
        ignore_dups: Boolean; if False, abort on duplicate entries without inserting
        anything

    Returns:
        An empty json response body

    Exceptions:
        HTTP 400: Request content-type is not 'text/plain'
        HTTP 400: Malformed SHA
        HTTP 404: Project not found
        HTTP 409: ignore_dups=False and there are duplicate entries
        HTTP 500: Multiple projects found with matching project name
    """
    if request.content_type != 'text/plain':
        abort(
            400, "HTTP request header 'Content-Type' must be set to 'text/plain'")
    session = g.db.session(DB_DECLARATIVE_BASE)
    proj = _get_project(session, project)  # can raise HTTP 404 or HTTP 500
    for line in request.stream.readlines():
        line = line.rstrip()
        try:
            (git_commit, hg_changeset) = line.split(' ')
        except ValueError:
            logger.error(
                "Received input line: '%s' for project %s", line, project)
            logger.error("Was expecting an input line such as "
                         "'686a558fad7954d8481cfd6714cdd56b491d2988 "
                         "fef90029cb654ad9848337e262078e403baf0c7a'")
            logger.error("i.e. where the first hash is a git commit SHA "
                         "and the second hash is a mercurial changeset SHA")
            abort(400, "Input line '%s' received for project %s did not contain a space"
                  % (line, project))
            # header/footer won't match this format
            continue
        _add_hash(session, git_commit, hg_changeset, proj)  # can raise HTTP 400
        if ignore_dups:
            try:
                session.commit()
            except sa.exc.IntegrityError:
                session.rollback()
    if not ignore_dups:
        try:
            session.commit()
        except sa.exc.IntegrityError:
            session.rollback()
            abort(409, "Some of the given mappings for project %s already exist"
                  % project)
    return jsonify() 
Example #27
Source File: __init__.py    From zimfarm with GNU General Public License v3.0 4 votes vote down vote up
def credentials():
    """
    Authorize a user with username and password
    When success, return json object with access and refresh token
    """

    # get username and password from request header
    if "application/x-www-form-urlencoded" in request.content_type:
        username = request.form.get("username")
        password = request.form.get("password")
    else:
        username = request.headers.get("username")
        password = request.headers.get("password")
    if username is None or password is None:
        raise BadRequest("missing username or password")

    # check user exists
    user = Users().find_one(
        {"username": username}, {"username": 1, "scope": 1, "password_hash": 1}
    )
    if user is None:
        raise Unauthorized("this user does not exist")

    # check password is valid
    password_hash = user.pop("password_hash")
    is_valid = check_password_hash(password_hash, password)
    if not is_valid:
        raise Unauthorized("password does not match")

    # generate token
    access_token = AccessToken.encode(user)
    access_expires = AccessToken.get_expiry(access_token)
    refresh_token = create_refresh_token(user["username"])

    # send response
    response_json = {
        "access_token": access_token,
        "token_type": "bearer",
        "expires_in": access_expires,
        "refresh_token": refresh_token,
    }
    response = jsonify(response_json)
    response.headers["Cache-Control"] = "no-store"
    response.headers["Pragma"] = "no-cache"
    return response