File: resource-server.rst

package info (click to toggle)
python-authlib 1.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,016 kB
  • sloc: python: 26,998; makefile: 53; sh: 14
file content (137 lines) | stat: -rw-r--r-- 3,918 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
.. _flask_oauth2_resource_protector:

Resource Server
===============

Protects users resources, so that only the authorized clients with the
authorized access token can access the given scope resources.

A resource server can be a different server other than the authorization
server. Authlib offers a **decorator** to protect your API endpoints::

    from flask import jsonify
    from authlib.integrations.flask_oauth2 import ResourceProtector, current_token
    from authlib.oauth2.rfc6750 import BearerTokenValidator

    class MyBearerTokenValidator(BearerTokenValidator):
        def authenticate_token(self, token_string):
            return Token.query.filter_by(access_token=token_string).first()

    require_oauth = ResourceProtector()

    # only bearer token is supported currently
    require_oauth.register_token_validator(MyBearerTokenValidator())

When the resource server has no access to the ``Token`` model (database), and
there is an introspection token endpoint in authorization server, you can
:ref:`require_oauth_introspection`.

Here is the way to protect your users' resources::

    @app.route('/user')
    @require_oauth('profile')
    def user_profile():
        # if Token model has `.user` foreign key
        user = current_token.user
        return jsonify(user)

If the resource is not protected by a scope, use ``None``::

    @app.route('/user')
    @require_oauth()
    def user_profile():
        user = current_token.user
        return jsonify(user)

    # or with None

    @app.route('/user')
    @require_oauth(None)
    def user_profile():
        user = current_token.user
        return jsonify(user)

The ``current_token`` is a proxy to the Token model you have defined above.
Since there is a ``user`` relationship on the Token model, we can access this
``user`` with ``current_token.user``.

If the decorator is not your favorite, there is a ``with`` statement for you::

    @app.route('/user')
    def user_profile():
        with require_oauth.acquire('profile') as token:
            user = token.user
            return jsonify(user)

.. _flask_oauth2_multiple_scopes:

Multiple Scopes
---------------

.. versionchanged:: v1.0

You can apply multiple scopes to one endpoint in **AND**, **OR** and mix modes.
Here are some examples:

.. code-block:: python

    @app.route('/profile')
    @require_oauth(['profile email'])
    def user_profile():
        user = current_token.user
        return jsonify(user)

It requires the token containing both ``profile`` and ``email`` scope.

.. code-block:: python

    @app.route('/profile')
    @require_oauth(['profile', 'email']')
    def user_profile():
        user = current_token.user
        return jsonify(user)

It requires the token containing either ``profile`` or ``email`` scope.

It is also possible to mix **AND** and **OR** logic. e.g.::

    @app.route('/profile')
    @require_oauth(['profile email', 'user'])
    def user_profile():
        user = current_token.user
        return jsonify(user)

This means if the token will be valid if:

1. token contains both ``profile`` and ``email`` scope
2. or token contains ``user`` scope

Optional ``require_oauth``
--------------------------

There is one more parameter for ``require_oauth`` which is used to serve
public endpoints::

    @app.route('/timeline')
    @require_oauth(optional=True)
    def timeline_api():
        if current_token:
            return get_user_timeline(current_token.user)
        return get_public_timeline()

MethodView & Flask-Restful
--------------------------

You can also use the ``require_oauth`` decorator in ``flask.views.MethodView``
and ``flask_restful.Resource``::

    from flask.views import MethodView

    class UserAPI(MethodView):
        decorators = [require_oauth('profile')]


    from flask_restful import Resource

    class UserAPI(Resource):
        method_decorators = [require_oauth('profile')]