Skip to content

Commit 5ca4c41

Browse files
committed
Implemented the Approov protected server.
Signed-off-by: Exadra37 <exadra37@gmail.com>
1 parent 170d84b commit 5ca4c41

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# For production usage the secret is always retrieved with the Approov CLI tool, that can be also used to generate valid
2+
# tokens for testing purposes. Check docs at https://approov.io/docs/v2.1/approov-cli-tool-reference/#token-commands.
3+
#
4+
# But if you don't have the Approov CLI tool, you can still test the backend with Postman or similar, by creating a
5+
# secret with `openssl rand -base64 64 | tr -d '\n'; echo`, and afterwards you can use jwt.io to create the JWT token.
6+
APPROOV_BASE64_SECRET=approov_base64_secret_here
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Approov Token Integration Example
2+
3+
This Approov integration example is from where the code example for the [Approov token check quickstart](/docs/APPROOV_TOKEN_QUICKSTART.md) is extracted, and you can use it as a playground to better understand how simple and easy it is to implement [Approov](https://approov.io) in a Python FastAPI server.
4+
5+
## TOC - Table of Contents
6+
7+
* [Why?](#why)
8+
* [How it Works?](#how-it-works)
9+
* [Requirements](#requirements)
10+
* [Try the Approov Integration Example](#try-the-approov-integration-example)
11+
12+
13+
## Why?
14+
15+
To lock down your API server to your mobile app. Please read the brief summary in the [README](/README.md#why) at the root of this repo or visit our [website](https://approov.io/product.html) for more details.
16+
17+
[TOC](#toc---table-of-contents)
18+
19+
20+
## How it works?
21+
22+
The Python FastAPI server is very simple and is defined in the file [src/approov-protected-server/token-check/hello-server-protected.py](src/approov-protected-server/token-check/hello-server-protected.py). Take a look at the `verifyApproovToken()` function to see the simple code for the check.
23+
24+
For more background on Approov, see the overview in the [README](/README.md#how-it-works) at the root of this repo.
25+
26+
[TOC](#toc---table-of-contents)
27+
28+
29+
## Requirements
30+
31+
To run this example you will need to have installed:
32+
33+
* [Python 3](https://wiki.python.org/moin/BeginnersGuide/Download)
34+
* [FastAPI](https://fastapi.tiangolo.com/tutorial/#install-fastapi)
35+
36+
[TOC](#toc---table-of-contents)
37+
38+
39+
## Try the Approov Integration Example
40+
41+
First, you need to set the dummy secret in the `src/approov-protected-server/token-check/.env` file as explained [here](/README.md#the-dummy-secret).
42+
43+
Second, you need to install the dependencies. From the `src/approov-protected-server/token-check` folder execute:
44+
45+
```text
46+
virtualenv venv
47+
source venv/bin/activate
48+
pip3 install -r requirements.txt
49+
```
50+
51+
Now, you can run this example from the `src/approov-protected-server/token-check` folder with:
52+
53+
```text
54+
uvicorn hello-server-protected:app --reload --port 8002
55+
```
56+
> **NOTE:** If using python from inside a docker container add the option `--host 0.0.0.0`
57+
58+
Finally, you can test that the Approov integration example works as expected with this [Postman collection](/README.md#testing-with-postman) or with some cURL requests [examples](/README.md#testing-with-curl).
59+
60+
[TOC](#toc---table-of-contents)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from fastapi import FastAPI, HTTPException, Request
2+
from fastapi.responses import JSONResponse
3+
4+
import base64
5+
6+
# @link https://github.com/jpadilla/pyjwt/
7+
import jwt
8+
9+
# @link https://github.com/theskumar/python-dotenv
10+
from dotenv import load_dotenv, find_dotenv
11+
load_dotenv(find_dotenv(), override=True)
12+
from os import getenv
13+
14+
# Token secret value obtained with the Approov CLI tool:
15+
# - approov secret -get
16+
approov_base64_secret = getenv('APPROOV_BASE64_SECRET')
17+
18+
if approov_base64_secret == None:
19+
raise ValueError("Missing the value for environment variable: APPROOV_BASE64_SECRET")
20+
21+
APPROOV_SECRET = base64.b64decode(approov_base64_secret)
22+
23+
app = FastAPI()
24+
25+
# @link https://approov.io/docs/latest/approov-usage-documentation/#backend-integration
26+
@app.middleware("http")
27+
async def verifyApproovToken(request: Request, call_next):
28+
approov_token = request.headers.get("Approov-Token")
29+
30+
# If we didn't find a token, then reject the request.
31+
if approov_token == "":
32+
# You may want to add some logging here.
33+
# return None
34+
return JSONResponse({}, status_code = 401)
35+
36+
try:
37+
# Decode the Approov token explicitly with the HS256 algorithm to avoid
38+
# the algorithm None attack.
39+
approov_token_claims = jwt.decode(approov_token, APPROOV_SECRET, algorithms=['HS256'])
40+
return await call_next(request)
41+
except jwt.ExpiredSignatureError as e:
42+
# You may want to add some logging here.
43+
return JSONResponse({}, status_code = 401)
44+
except jwt.InvalidTokenError as e:
45+
# You may want to add some logging here.
46+
return JSONResponse({}, status_code = 401)
47+
48+
49+
@app.get("/")
50+
async def root():
51+
return {"message": "Hello World"}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
click==7.1.2
2+
fastapi==0.63.0
3+
h11==0.12.0
4+
pydantic==1.8.1
5+
PyJWT==2.0.1
6+
python-dotenv==0.15.0
7+
starlette==0.13.6
8+
typing-extensions==3.7.4.3
9+
uvicorn==0.13.4

0 commit comments

Comments
 (0)