Skip to content

Commit 94f468b

Browse files
authored
Merge pull request #10 from Annyv2/oidc
OIDC Updates
2 parents 1db6fed + e9197fe commit 94f468b

4 files changed

Lines changed: 51 additions & 37 deletions

File tree

00-Starter-Seed/.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
AUTH0_CLIENT_ID={CLIENT_ID}
2-
AUTH0_CLIENT_SECRET={CLIENT_SECRET}
1+
AUTH0_DOMAIN={AUTH0_DOMAIN}
2+
API_ID={API_AUDIENCE}

00-Starter-Seed/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Auth0 + Python + Flask API Seed
2-
This is the seed project you need to use if you're going to create a Python + Flask API. You'll mostly use this API either for a SPA or a Mobile app. If you just want to create a Regular Python WebApp, please check [this other seed project](https://github.com/auth0-samples/auth0-python-web-app/tree/master/00-Starter-Seed)
2+
This is the seed project you need to use if you're going to create a Python + Flask API. If you just want to create a Regular Python WebApp, please check [this other seed project](https://github.com/auth0-samples/auth0-python-web-app/tree/master/00-Starter-Seed)
33

44
# Running the example
55
In order to run the example you need to have `python` and `pip` installed.
66

7-
You also need to set the client secret and ID of your Auth0 app as environment variables with the following names respectively: `AUTH0_CLIENT_SECRET` and `AUTH0_CLIENT_ID`.
7+
You also need to set your Auth0 Domain and the API's audience as environment variables with the following names respectively: `AUTH0_DOMAIN` and `API_ID`, which is the audience of your API. You can find an example in the `env.example` file.
88

99
For that, if you just create a file named `.env` in the directory and set the values like the following, the app will just work:
1010

1111
```bash
1212
# .env file
13-
AUTH0_CLIENT_SECRET=YOUR_CLIENT_SECRET
14-
AUTH0_CLIENT_ID=YOUR_CLIENT_ID
13+
AUTH0_DOMAIN=example.auth0.com
14+
API_ID=YOUR_API_AUDIENCE
1515
```
1616

1717
Once you've set those 2 enviroment variables:
@@ -20,4 +20,4 @@ Once you've set those 2 enviroment variables:
2020
2. Start the server with `python server.py`
2121
3. Try calling [http://localhost:3001/ping](http://localhost:3001/ping)
2222

23-
You can then try to do a GET to [http://localhost:3001/secured/ping](http://localhost:3001/secured/ping) which will throw an error if you don't send the JWT signed using HMAC-SHA256 in the header.
23+
You can then try to do a GET to [http://localhost:3001/secured/ping](http://localhost:3001/secured/ping) which will throw an error if you don't send an access token signed with RS256 with the appropriate issuer and audience in the Authorization header

00-Starter-Seed/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
flask
22
python-dotenv
3-
PyJWT
3+
python-jose
44
flask-cors

00-Starter-Seed/server.py

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import jwt
2-
1+
import json
32
from os import environ as env, path
3+
import urllib
4+
45
from dotenv import load_dotenv
56
from functools import wraps
67
from flask import Flask, request, jsonify, _app_ctx_stack
78
from flask_cors import cross_origin
9+
from jose import jwt
810

911
load_dotenv(path.join(path.dirname(__file__), '.env'))
10-
client_id = env["AUTH0_CLIENT_ID"]
11-
client_secret = env["AUTH0_CLIENT_SECRET"]
12+
auth0_domain = env['AUTH0_DOMAIN']
13+
api_audience = env['API_ID']
1214

1315
app = Flask(__name__)
1416

@@ -45,31 +47,43 @@ def decorated(*args, **kwargs):
4547
'Bearer + \s + token'}, 401)
4648

4749
token = parts[1]
48-
try:
49-
payload = jwt.decode(
50-
token,
51-
client_secret,
52-
audience=client_id
53-
)
54-
except jwt.ExpiredSignatureError:
55-
return handle_error({'code': 'token_expired',
56-
'description': 'token is expired'}, 401)
57-
except jwt.InvalidAudienceError:
58-
return handle_error({'code': 'invalid_audience',
59-
'description': 'incorrect audience, expected: '
60-
+ client_id}, 401)
61-
except jwt.DecodeError:
62-
return handle_error({'code': 'token_invalid_signature',
63-
'description':
64-
'token signature is invalid'}, 401)
65-
except Exception:
66-
return handle_error({'code': 'invalid_header',
67-
'description': 'Unable to parse authentication'
68-
' token.'}, 400)
69-
70-
_app_ctx_stack.top.current_user = payload
71-
return f(*args, **kwargs)
72-
50+
jsonurl = urllib.urlopen('https://'+auth0_domain+'/.well-known/jwks.json')
51+
jwks = json.loads(jsonurl.read())
52+
unverified_header = jwt.get_unverified_header(token)
53+
rsa_key = {}
54+
for key in jwks['keys']:
55+
if key['kid'] == unverified_header['kid']:
56+
rsa_key = {
57+
'kty': key['kty'],
58+
'kid': key['kid'],
59+
'use': key['use'],
60+
'n': key['n'],
61+
'e': key['e']
62+
}
63+
if rsa_key:
64+
try:
65+
payload = jwt.decode(
66+
token,
67+
rsa_key,
68+
algorithms=unverified_header['alg'],
69+
audience=api_audience,
70+
issuer='https://'+auth0_domain+'/'
71+
)
72+
except jwt.ExpiredSignatureError:
73+
return handle_error({'code': 'token_expired',
74+
'description': 'token is expired'}, 401)
75+
except jwt.JWTClaimsError:
76+
return handle_error({'code': 'invalid_claims',
77+
'description': 'incorrect claims, please check the audience and issuer'}, 401)
78+
except Exception:
79+
return handle_error({'code': 'invalid_header',
80+
'description': 'Unable to parse authentication'
81+
' token.'}, 400)
82+
83+
_app_ctx_stack.top.current_user = payload
84+
return f(*args, **kwargs)
85+
return handle_error({'code': 'invalid_header',
86+
'description': 'Unable to find appropriate key'}, 400)
7387
return decorated
7488

7589

0 commit comments

Comments
 (0)