diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..b3bc1a3 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,4794 @@ + + +
+ ++Used for authentication/authorization such as: +
+ + ++Imagine app with many features + servers + engineers: +
+ +
+
+
+
+
+Auth Server has secrets; needs security + maintenance +
+ ++Base64 encoded header.payload.signature: +
+ +HEADER: { "alg": "EdDSA", "typ": "JWT" }
+
+PAYLOAD: {"sub": "a", "name": "arbitrary data", "iat": 1 }
+
+SIGNATURE: SU6aXJ0YbH7Vg1jROpQfvnhn98Rt9zBeS7-c5O9jH-L
+ L5mQqMMFq61eZjf0tLLqExm-dckRUNa3-qT7R2SKmCw
+
+
+ENCODED JWT: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9
+ .eyJzdWIiOiJhIiwibmFtZSI6ImIiLCJpYXQiOjF9
+ .SU6aXJ0YbH7Vg1jROpQfvnhn98Rt9zBeS7-c5O9jH-L
+ L5mQqMMFq61eZjf0tLLqExm-dckRUNa3-qT7R2SKmCw
+
++Signed using EdDSA with secret key: +
+ +MC4CAQAwBQYDK2VwBCIEIC+D6rD2YbXtV0ccR3smoR0ynhVuyyqvplFLbQWDdAtn
+
+pyjwt)
+@app.route('/support/urgent') # built-in flask decorator
+@requires_jwt # custom decorator to validate JWT
+@jwt_claims(['paid_support']) # ensures token is for premium user
+@jwt_iat(datetime.timedelta(hours=24)) # ensure recent token
+def support_urgent():
+ ... # process ending support request
+
+pyjwt)
+@app.route('/support/urgent') # built-in flask decorator
+@requires_jwt # custom decorator to validate JWT
+@jwt_claims(['paid_support']) # ensures token is for premium user
+@jwt_iat(datetime.timedelta(hours=24)) # ensure recent token
+def support_urgent():
+ ... # process ending support request
+
+pyjwt)
+@app.route('/support/urgent') # built-in flask decorator
+@requires_jwt # custom decorator to validate JWT
+@jwt_claims(['paid_support']) # ensures token is for premium user
+@jwt_iat(datetime.timedelta(hours=24)) # ensure recent token
+def support_urgent():
+ ... # process ending support request
+
+pyjwt)
+@app.route('/support/urgent') # built-in flask decorator
+@requires_jwt # custom decorator to validate JWT
+@jwt_claims(['paid_support']) # ensures token is for premium user
+@jwt_iat(datetime.timedelta(hours=24)) # ensure recent token
+def support_urgent():
+ ... # process ending support request
+
+pyjwt)
+@app.route('/support/urgent') # built-in flask decorator
+@requires_jwt # custom decorator to validate JWT
+@jwt_claims(['paid_support']) # ensures token is for premium user
+@jwt_iat(datetime.timedelta(hours=24)) # ensure recent token
+def support_urgent():
+ ... # process ending support request
+
+@requires_jwtdef requires_jwt(func):
+ @wraps(func)
+ def decorated(*args, **kwargs):
+ token = request.headers.get("Authorization").split(" ")[1]
+ if not token:
+ return 'missing token', 401 # if no token return error
+ try:
+ g.decoded_jwt = jwt.decode(
+ token, algorithms=['EdDSA'],
+ key=current_app.config['JWT_KEY']) # public key
+ return func(*args, **kwargs)
+ except Exception as problem:
+ return f'{problem=}', 401 # return 401 or other error code
+ return decorated
+
+@jwt_claimsdef jwt_claims(claims_list: typing.Sequence[str]):
+ def make_decorator(func):
+ @wraps(func)
+ def decorated(*args, **kwargs):
+ missing = [c for c in claims_list
+ if not g.decoded_jwt.get(c)]
+ if missing:
+ return f'Missing claims: {missing}', 401
+ return func(*args, **kwargs)
+ return decorated
+ return make_decorator
+
+{"sub": "Alice", "proxy": "Bob"}{"sub": "Alice", "proxy": "Bob"}@APP.route("/issue")
+@requires_jwt
+def issue():
+ "Example route to create an issue."
+ user = g.decoded_jwt.get('proxy', g.decoded_jwt.get('sub'))
+ msg = f'Created issue assigned to {user}.'
+ # ... Create the actual issue here
+
+
+
+ return msg
+
+{"sub": "Alice", "proxy": "Bob"}@APP.route("/issue")
+@requires_jwt
+def issue():
+ "Example route to create an issue."
+ user = g.decoded_jwt.get('proxy', g.decoded_jwt.get('sub'))
+ msg = f'Created issue assigned to {user}.'
+ # ... Create the actual issue here
+ real_user = g.decoded_jwt['sub']
+ if real_user != user:
+ msg += f'\n{real_user} acted on behalf of {user}'
+ return msg
+
+alg field or limit possibilities
+algorithms=['EdDSA']kid, jku, jwk, etc.{alg: "EdDSA", jku: "https://good.com/pk.json"}{alg: "EdDSA", jku: "https://bad.com/pk.json"}{alg: "EdDSA", jku: "https://good.com/pk.json"}{alg: "HS256", jku: "https://good.com/pk.json"}
+
+
+
+
+e.g., NGINX can verify before passing to app server +
+ +
+
nginx directory on github.com/aocks/ox_jwt{alg: "HS256", jku: "https://bad.com/pk.json"}{alg: "HS256", jku: "https://good.com/pk.json"}