Authentication Schemes Strategy¶
Authentication scheme is another strategy for identifying the user who is using the application. The difference between it and and Guard strategy is your identification executed at middleware layer when processing incoming request while guard execution happens just before route function is executed.
Ellar provides BaseAuthenticationHandler
contract which defines what is required to set up any authentication strategy. We are going to make some modifications on the existing project to see how we can achieve the same result and to show how authentication handlers in ellar.
Creating a JWT Authentication Handler¶
Just like AuthGuard, we need to create its equivalent. But first we need to create a auth_scheme.py
at the root level of your application for us to define a JWTAuthentication
handler.
project_name/auth_scheme.py | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Let us make JWTAuthentication
Handler available for ellar to use as shown below
project_name.server.py | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
GlobalGuard
registration we did in AuthModule
, so that we don't have too user identification checks. Note
In the above illustration, we added JWTAuthentication as a type. This means DI will create JWTAuthentication instance. We can use this method because we want JWTService
to be injected when instantiating JWTAuthentication
. But if you don't have any need for DI injection, you can use the below.
...
application.add_authentication_schemes(JWTAuthentication())
## OR
## use_authentication_schemes(JWTAuthentication())
We need to refactor auth controller and mark refresh_token
and sign_in
function as public routes by using SkipAuth
decorator from ellar.auth
package.
auth/controller.py | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
@AuthenticationRequired('JWTAuthentication')
to ensure we have authenticated user before executing any route function and, we passed in JWTAuthentication
as a parameter, which will be used in openapi doc to define the controller routes security scheme. It is importance to note that when using AuthenticationHandler
approach, that you have to always use AuthenticationRequired
decorator on route functions or controller that needs protected from anonymous users.
But if you have a single form of authentication, you can register AuthenticatedRequiredGuard
from eellar.auth.guard
module globally just like we did in applying guard globally
auth/module.py | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Still having the server running, we can test as before
$ # GET /auth/profile
$ curl http://localhost:8000/auth/profile
{"detail":"Forbidden"} # status_code=403
$ # POST /auth/login
$ curl -X POST http://localhost:8000/auth/login -d '{"username": "john", "password": "password"}' -H "Content-Type: application/json"
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTg3OTE0OTE..."}
$ # GET /profile using access_token returned from previous step as bearer code
$ curl http://localhost:8000/auth/profile -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2Vybm..."
{"exp":1698793558,"iat":1698793258,"jti":"e96e94c5c3ef4fbbbd7c2468eb64534b","sub":1,"user_id":1,"username":"john", "id":null,"auth_type":"bearer"}