Setting up the API Client Model
Add a new files models/client.py and add the code below. This model will store an API clients access credentials. The client_id is used to identify a Client. The secret_key is used to encode and decode JSON Web Tokens.
Now import the Client model in models/__init__.py
Now create and apply a database migration
$ docker-compose run api flask db revision "add client model"
$ docker-compose run api flask db upgrade
Identifying the API Client — Using Arrested’s middleware system
Flask comes with a great system for defining request middleware. Arrested builds on top of this system to allow more fine grained control of where and when your middleware is run.
Middleware can be applied at each level of the Arrested stack. You will often want a piece of middleware to be applied across every resource and every endpoint defined in an API. In our case authentication.
For those of you that followed along in the first post you might remember seeing some middleware in action already. The Arrested cookie cutter creates has middleware that authenticates requests using Basic Auth by default.
We now require that all requests are made with an ?api_key that we’ll use to identify the Client making request.
First we’ll add a few functions that will allow us to encode and decode the tokens.
Create a new file apis/v1/utils.py and add the following code.
Open up apis/v1/middleware.py and add the get_api_client_from_request method.
Now add the middleware to the before_all_hooks list on our ArrestedAPI object in apis/v1/__init__.py
Now let’s try making a request to the Characters API.
Authenticating requests using JWTs.
In this section we’ll implement the middleware to authenticate requests using JSON Web Tokens.
Add the get_client_token function to apis/v1/middleware.py
Now add the middleware to our v1 ArrestedAPI object just like we did in step 2. We also removed the basic_auth middleware.
Now make a request to the API.
Apis with keys
This is the most common form of authentication when consuming APIs. The API Key/Token is passed in as a header while making the request. We will be working with the Cat as a Service (CAAS) API. You can get a key here
Background
We’ve decided that requests to our API should be authenticated using JSON Web Tokens.
Here’s a breakdown of what we’re going to cover in this post.
- Create a new
Client
Model. - Add our first piece of middleware to ensure that all requests are made with a valid
?api_key
- Add middleware & utility code for authenticating JWT’s pulled from the
Authorization
header.
In this post we’ll show you how to set up authentication for your python rest api using json web tokens.
In our first post we introduced you to Arrested — a framework for rapidly building robust REST APIs on top of Flask. In this post we’ll show you how to authenticate all requests to your APIs using JSON Web Tokens.
We will be following on from our first post using Arrested’s middleware system to show how easy it is to extend your Arrested APIs. If you’re not using Arrested don’t worry, a lot of the code outlined in this tutorial is reusable.
Insecure apis
The Cat Facts API does not require any authentication and is fairly straightforward to work with. Let’s make a request to the following endpoint
Oauth 2 and openid connect authentication¶
The requests-oauthlib library also handles OAuth 2, the authentication mechanism
underpinning OpenID Connect. See the requests-oauthlib OAuth2 documentation for
details of the various OAuth 2 credential management flows:
Other authentication¶
Requests is designed to allow other forms of authentication to be easily and
quickly plugged in. Members of the open-source community frequently write
authentication handlers for more complicated or less commonly-used forms of
authentication. Some of the best have been brought together under the
Requests organization, including:
If you want to use any of these forms of authentication, go straight to their
GitHub page and follow the instructions.
Reading from .env files
Before moving on to the next sections, let’s look at how to read variables from a .env file. It’s highly recommended to store your credentials in a .env file to avoid them being exposed to others.
We will need to install the python-dotenv library.
pip install python-dotenv
Assume have a .env file with some random API Token
API_TOKEN = "SOME API TOKEN"
Let’s try reading the API Token in Python.
from dotenv import load_dotenv
import os
load_dotenv()
API_TOKEN = os.environ.get("API_TOKEN")
The get function accepts a variable name stored in the .env file as an argument.
Resources
Github Repo
Setting up
👋 Quick Start. If you want to get started quickly you can use the arrested cookie-cutter template to create a project that includes all of the steps covered in the first post.
Table of contents
- Insecure APIs
- Reading values from.env files
- APIs with Keys
- APIs with Basic Auth
- API Wrappers
- The Session Object
- APIs secured via OAuth2
- Using the GitHub API (OAuth2)
- Using the Genius API (OAuth2)
Some familiarity with the requests library is expected. If you need a refresher, you can refer to my previous article.
Using the genius api (oauth2)
Let’s take a look at another example. I’ll skip the part where we import the libraries and load the credentials.
Выход из системы
Мы реализовали вход, самое время добавить возможность выхода из системы. Это делается очень просто (файл app/views.py):
Заключительные слова
Теперь у нас есть полноценная система для авторизации пользователей. В следующей главе мы создадим страницу профиля пользователя, и добавим возможность использования аватаров.
Конфигурация
Как и в предыдущих главах, мы начнём с настройки расширений, которые будем использовать. Для авторизации нам понадобятся два расширения — Flask-Login и Flask-OpenID. Настроим их следующим образом (файл app/__init__.py):
import os
from flask.ext.login import LoginManager
from flask.ext.openid import OpenID
from config import basedir
lm = LoginManager()
lm.init_app(app)
oid = OpenID(app, os.path.join(basedir, 'tmp'))
Расширению Flask-OpenID нужно где-то хранить свои временные файлы, для этого при инициализации ему передаётся путь до папки tmp.
Краткое повторение
В предыдущей части мы создали базу данных и научились заполнять её пользователями и постами, однако этот функционал еще не реализован в нашем приложении. Две главы назад мы узнали, как создавать веб-формы и создали форму для авторизации.
В этой статье мы объединим наши знания о веб-формах и базах данных и напишем свою систему для входа пользователей. В конце данного руководства наше небольшое приложение будет регистрировать новых пользователей и проводить их авторизацию.
Для работы с этой главой ваше приложение должно быть таким, каким мы оставили его в конце предыдущей главы. Пожалуйста, убедитесь, что приложение установлено и работает.
Обработка ответа от провайдера openid
Так выглядит реализация функции after_login(файл app/views.py):
Отображение главной страницы
В предыдущей главе мы использовали в функции index объекты-заглушки, так как у нас еще не было настоящих пользователей и постов. Теперь у нас есть пользователи, самое время это использовать:
Функция представления авторизации
Давайте обновим нашу функцию представления (файл app/views.py):
Conclusion
I hope this article serves as a good guide to work with APIs in Python. Before consuming an API directly, always look for a wrapper. The 5 mins you spend looking for a wrapper might save you hours of headache.