Creating Secure API’s with EasyAuth & FastAPI

Joshua Jamison
ITNEXT
Published in
5 min readMay 4, 2021

--

This article will walk through securing an existing FastAPI application with EasyAuth

APP LAYOUT├── app
│ ├── __init__.py
│ ├── main.py
│ └── marketing
│ │ ├── __init__.py
│ │ ├── marketing.py
│ └── finance
│ │ ├── __init__.py
│ │ ├── finance.py
│ └── hr
│ ├── __init__.py
│ └── hr.py

main.py

finance.py

A look at the API from the OpenAPI web page:

$ uvicorn --host 0.0.0.0 --port 8320 main:server
INFO: Started server process [93409]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8320 (Press CTRL+C to quit)
INFO: 127.0.0.1:46184 - "GET / HTTP/1.1" 404 Not Found
INFO: 127.0.0.1:46184 - "GET /docs HTTP/1.1" 200 OK
INFO: 127.0.0.1:46184 - "GET /openapi.json HTTP/1.1" 200 OK

Currently the API is accessible and usable by anyone with a network connection that can reach the server:

$ curl 0.0.0.0:8320/marketing/
"marketing_root"
$ curl 0.0.0.0:8320/finance/data
"finance_data"

Securing endpoints with EasyAuth

EasyAuth can be run as a standalone authentication service, or along side an existing application.

Creating a Standalone Auth Service

Instead of re-creating users, group, roles, & permission, centralize into a single auth service that can be used across many applications

  1. Prepare environment
$ virtualenv -p python3 auth-env
$ source auth-env/bin/activate

2. Install dependencies

(auth-env)$ pip install easy-auth[server]

3. Setup EasyAuthConfig file

4. Configure EasyAuthServer

5. Start Server

$ uvicorn --host 0.0.0.0 --port 8090 auth_server:serverINFO:     Started server process [115918]
INFO: Waiting for application startup.
.
..
...
05-04 17:09 EasyAuthServer ERROR detected new EasyAuth server, created admin user with password: rgpgltou
.
..
05-04 17:09 EasyAuthServer WARNING EasyAuthServer Started! - Loaded Tokens {}
05-04 17:09 EasyAuthServer WARNING adding routers
INFO: Application startup complete.
05-04 17:09 uvicorn.error INFO Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8090 (Press CTRL+C to quit)
05-04 17:09 uvicorn.error INFO Uvicorn running on http://0.0.0.0:8090 (Press CTRL+C to quit)

To access the GUI, browse to http://0.0.0.0:8090/admin and login using admin/rgpgltou

Using EasyAuth with an existing FastAPI Application

Securing an existing FastAPI application is possible with an EasyAuthServer or EasyAuthClient.

The next example will demonstrate using an EasyAuthClient connecting to the standalone EasyAuthServer just created, with the initial FastAPI app.

Prerequisite

$ pip install easy-auth[client]APP LAYOUT├── app
│ ├── __init__.py
│ ├── main.py
│ └── web
│ │ ├── __init__.py
│ │ ├── web.py
│ └── marketing
│ │ ├── __init__.py
│ │ ├── marketing.py
│ └── finance
│ │ ├── __init__.py
│ │ ├── finance.py
│ └── hr
│ ├── __init__.py
│ └── hr.py

Start the Application

$ uvicorn --host 0.0.0.0 --port 8190 main:server
INFO: Started server process [162292]
INFO: Waiting for application startup.
05-04 21:35 EasyRpc-server /ws/easyauth WARNING creating cron or get_upstream_registered_functions - interval 30
05-04 21:35 EasyRpc-server /ws/easyauth WARNING creating cron or get_upstream_registered_functions - interval 30
05-04 21:36 EasyAuthServer WARNING adding routers
INFO: Application startup complete.
05-04 21:36 uvicorn.error INFO Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8190 (Press CTRL+C to quit)

Notice that all endpoints have change in the OpenAPI docs requiring authentication.

And when accessing an endpoint with an HTMLResponse — /web/

Including exception handlers for 403, 404 & 401 responses:

Using EasyAuthServer next to an existing app

EasyAuthServer can also be plugged directly into an existing app, but requires the same server pre-requisites: config &dependencies:

EasyAuthServer endpoints & application endpoints are combined within OpenAPI docs

Authentication & Authorization

EasyAuth Authentication is based on Asymmetric RSA JSON Web Tokens, which guarantees web tokens used are valid. This great article on this subject.

EasyAuth Authorization implemented using an RBAC approach to provide granular control over endpoints.

RBAC

RBAC, or Role based access control, provides users with very specific sets of permissions based on assigned Groups, Roles, & Actions

Type — User

A user is defined as an end-user / service that accesses an endpoint.

A user requests a token by providing sending username & password

Type — service

Tokens for services must be generated by a user in administrators group — no password exist for service accounts

Permissions

Permissions are derived from the group or groups assigned to the specific user.

Group

Assigned to Users, and containing a list of specified roles.

Permissions are derived from the roles assigned to the specific group.

Role

Assigned to Groups, and containing a list of actions.

Permissions are derived from the Actions assigned to the specific Role

Action

Actions are the most granular permission that can be created to define something that can be allowed.

Tokens

Tokens are created for a specific user, that contain the full permissions tree for a specific user (Groups, Roles, Actions)

User Token — Expiration

Expires after ~ 60 Minutes

Service Token — Expiration

Expires ~900 days

Cookies are invalidated by the EasyAuthClient if the token inside the cookie has expired / revoked

Revoking a Token

Once a token is created, it is valid until expiration or EasyAuthServer rsa key rotation.

EasyAuthServer maintains a token registry of issued tokens, containing the underlying username, issue date, expiration_date & token_id.

EasyAuthServer updates all EasyAuthServer workers & connected EasyAuthClients when a token is added / revoked.

Tokens listed in the registry are seen as valid, and tokens which are revoked or do not exist in the registry, will return a 403.

Resources

The most comprehensive documentation is available here

Contribute

EasyAuth is constantly improving, have an idea, suggestion, bug? Create an issue!

--

--