13 - JWT Authentication at API-Gateway web
Table of contents
Till now we had two end pointsi in API-Gateway-web
Authentication - to validate the user credentials
Registration - Allows any user to register in the application
Today we shall be developing a third end point i.e execute end point which will handle the logic after the customer does a login like getting applicant details,updating applicant details,adding skill of applicants.
Add JWT authentication
Lets first add a method to validate the JWT token which is received when a user inputs username and password.
In the folder API-Gateway/commonlib we added a file auth_bearer_handler.py which will do the duty of autheticating a code. We shall be create a class JWTBearer which shall inhert HTTPBearer class in name space fastapi.security so the properties and methods of HTTPBearer are available in JWTBearer class
We shall add two methods verify_jwt and decode_jwt. The verify_jwt method will in turn call the decode_jwt method. Code is given below
def verify_jwt(self, jwtoken: str) -> bool:
is_token_valid: bool = False
try:
payload = self.decode_jwt(jwtoken)
except:
payload = None
if payload:
is_token_valid = True
return is_token_valid
@staticmethod
def decode_jwt(token: str) -> dict:
try:
decoded_token = jwt.decode(token.split(' ')[1], config.JWT_SECRET,
algorithms=[config.JWT_ALGORITHM])
return decoded_token if decoded_token["expires"] >= time.time() else None
except Exception as Ex:
return {}
Add an execute route
Lets add an execute route
We shall add execute.py in routers folder which will have a route execute and a method containing the implementation. Also we would need a model of data accepted and sent as response in execute route. So lets define this under models/execute.py
from pydantic import BaseModel, Json
from typing import Optional
class ExecutePostModel(BaseModel):
service: str
path: str
method: str
query: Optional[str]
data: Optional[dict] = {}
class ExecutePostResponseModel(BaseModel):
data: Optional[Json]
message: Optional[str]
status_code: int
The Post model contains
service we are hitting like api-backend,api-core
path - the path of end point
method - specifies if it is GET,POST OR DELETE
query - for GET calls we can specify params like userid or customerid
data - data to be sent for POST methods
The response model contains
data - the data returned by the api end point
message - any error message if the call errors out
status_code - values 200,400,405 based on the execution of call
Following will be implementation of execute route
Below will be main highlights
@router.post("/execute", response_model=execute.ExecutePostResponseModel, dependencies=[Depends(JWTBearer())],
tags=[router_tag])
dependencies=[Depends(JWTBearer())] handles the dependency injection
if gateway_post.method == 'GET':
request_response = requests.get(url=url,
headers=headers,
verify=False
)
elif gateway_post.method == 'POST':
request_response = requests.post(url=url,
headers=headers,
data=json.dumps(gateway_post.data),
verify=False
)
elif gateway_post.method == 'DELETE':
request_response = requests.delete(url=url,
headers=headers,
data=json.dumps(gateway_post.data),
verify=False
)
above lines use the requests library to call the backend service based on GET,POST and DELETE methods
The below code will construct the response model and return the json object
if request_response.status_code >= 400:
#logger.debug(message=f"API-Gateway-Web Execute", trace=f"Request='{str(request_response.request.__dict__)}' Response='{str(request_response.__dict__)}")
print("400 code")
if request_response.headers.get('content-type') == 'application/json':
try:
if request_response.text:
response_model.data = json.dumps(request_response.json())
except:
raise RuntimeError(f"There was an issue trying to decode the response in API-Gateway Execute. Request-Response='{str(request_response.text)}' Request-URL='{request_response.url}'")
response_model.status_code = request_response.status_code
response.status_code = request_response.status_code
return response_model.__dict__
Its time to Test !!!
Since we have now implemented this its time to test
We shall do the following steps
call the auth end point to get the token
call the execute end point with token and data
Step1 :
Calling auth end point. I made a call in POSTMAN and following is the response
Step2:
Calling the execute with the token we recieved in Step1 and payload. We shall try to get applicant details for id 1. So it will be a GET call with query parameters
place where token is added. the type of authorization will be Bearer
Our end point works perfectly and gives us access to many routes.