Creating Secure API’s with EasyAuth & FastAPI
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
- 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.