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
Use Introspection in Resource Server.
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)
Multiple Scopes¶
Changed in version v1.0.
You can apply multiple scopes to one endpoint in AND, OR and mix modes. Here are some examples:
@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.
@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:
token contains both
profile
andemail
scopeor 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')]