-
-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add token based api auth #217
Merged
Merged
Changes from 4 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
998813d
feat: adding token base api auth in example/demo
kaplanelad 58b56f2
feat: adding token base api auth in starters/saas
kaplanelad 17bb81f
feat: adding token base api auth in starters/rest-api
kaplanelad 80548ee
add new controller to snapshot
kaplanelad b194ce0
return 401 insdead of bad request
kaplanelad a6ff21b
refactor: introduce: Authenticable
jondot 92dcdb6
revert middleware in starters
kaplanelad ece71ef
auth: add JWTWithUser, using Authenticable
jondot bf193d4
Merge branch 'master' into add-token-based-api-auth
jondot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
//! Axum middleware for validating API key tokens. | ||
|
||
use async_trait::async_trait; | ||
use axum::{ | ||
extract::{FromRef, FromRequestParts}, | ||
http::request::Parts, | ||
}; | ||
use loco_rs::{app::AppContext, controller::middleware::auth, errors::Error}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::models::_entities::users; | ||
|
||
#[derive(Debug, Deserialize, Serialize)] | ||
// Represents the data structure for the API token. | ||
pub struct ApiToken { | ||
pub user: users::Model, | ||
} | ||
|
||
#[async_trait] | ||
// Implementing the `FromRequestParts` trait for `ApiToken` to enable extracting it from the request. | ||
impl<S> FromRequestParts<S> for ApiToken | ||
where | ||
AppContext: FromRef<S>, | ||
S: Send + Sync, | ||
{ | ||
type Rejection = Error; | ||
|
||
// Extracts `ApiToken` from the request parts. | ||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Error> { | ||
// Extract API key from the request header. | ||
let api_key = auth::extract_token_from_header(&parts.headers) | ||
.map_err(|e| Error::Unauthorized(e.to_string()))?; | ||
|
||
// Convert the state reference to the application context. | ||
let state: AppContext = AppContext::from_ref(state); | ||
|
||
// Retrieve user information based on the API key from the database. | ||
let user = users::Model::find_by_api_key(&state.db, &api_key).await?; | ||
jondot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Ok(Self { user }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod api_key; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod auth; | ||
pub mod middleware; | ||
pub mod notes; | ||
pub mod user; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,22 @@ | ||
use loco_rs::prelude::*; | ||
|
||
use crate::controllers::middleware::api_key::ApiToken; | ||
use crate::{models::_entities::users, views::user::CurrentResponse}; | ||
use loco_rs::prelude::*; | ||
|
||
async fn current(auth: auth::JWT, State(ctx): State<AppContext>) -> Result<Json<CurrentResponse>> { | ||
let user = users::Model::find_by_pid(&ctx.db, &auth.claims.pid).await?; | ||
format::json(CurrentResponse::new(&user)) | ||
} | ||
|
||
async fn current_by_api_key( | ||
auth: ApiToken, | ||
State(_ctx): State<AppContext>, | ||
) -> Result<Json<CurrentResponse>> { | ||
format::json(CurrentResponse::new(&auth.user)) | ||
} | ||
|
||
pub fn routes() -> Routes { | ||
Routes::new().prefix("user").add("/current", get(current)) | ||
Routes::new() | ||
.prefix("user") | ||
.add("/current", get(current)) | ||
.add("/current_api_key", get(current_by_api_key)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,15 @@ | |
pid: 11111111-1111-1111-1111-111111111111 | ||
email: [email protected] | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY" | ||
api_key: lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758 | ||
name: user1 | ||
created_at: "2023-11-12T12:34:56.789" | ||
updated_at: "2023-11-12T12:34:56.789" | ||
- id: 2 | ||
pid: 22222222-2222-2222-2222-222222222222 | ||
email: [email protected] | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY" | ||
api_key: lo-153561ca-fa84-4e1b-813a-c62526d0a77e | ||
name: user2 | ||
created_at: "2023-11-12T12:34:56.789" | ||
updated_at: "2023-11-12T12:34:56.789" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,5 +91,6 @@ $ blo-cli routes | |
[DELETE] /notes/:id | ||
[POST] /notes/:id | ||
[GET] /user/current | ||
[GET] /user/current_api_key | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: PID, | ||
email: "[email protected]", | ||
password: "PASSWORD", | ||
api_key: "lo-PID", | ||
name: "framework", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: 11111111-1111-1111-1111-111111111111, | ||
email: "[email protected]", | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY", | ||
api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", | ||
name: "user1", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: 11111111-1111-1111-1111-111111111111, | ||
email: "[email protected]", | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY", | ||
api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", | ||
name: "user1", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
8 changes: 8 additions & 0 deletions
8
examples/demo/tests/requests/snapshots/can_get_current_user_with_api_key@auth_request.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
source: tests/requests/user.rs | ||
expression: "(response.status_code(), response.text())" | ||
--- | ||
( | ||
200, | ||
"{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"[email protected]\"}", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: PID, | ||
email: "[email protected]", | ||
password: "PASSWORD", | ||
api_key: "lo-PID", | ||
name: "loco", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
//! Axum middleware for validating API key tokens. | ||
|
||
use async_trait::async_trait; | ||
use axum::{ | ||
extract::{FromRef, FromRequestParts}, | ||
http::request::Parts, | ||
}; | ||
use loco_rs::{app::AppContext, controller::middleware::auth, errors::Error}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::models::_entities::users; | ||
|
||
#[derive(Debug, Deserialize, Serialize)] | ||
// Represents the data structure for the API token. | ||
pub struct ApiToken { | ||
pub user: users::Model, | ||
} | ||
|
||
#[async_trait] | ||
// Implementing the `FromRequestParts` trait for `ApiToken` to enable extracting it from the request. | ||
impl<S> FromRequestParts<S> for ApiToken | ||
where | ||
AppContext: FromRef<S>, | ||
S: Send + Sync, | ||
{ | ||
type Rejection = Error; | ||
|
||
// Extracts `ApiToken` from the request parts. | ||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Error> { | ||
// Extract API key from the request header. | ||
let api_key = auth::extract_token_from_header(&parts.headers) | ||
.map_err(|e| Error::Unauthorized(e.to_string()))?; | ||
|
||
// Convert the state reference to the application context. | ||
let state: AppContext = AppContext::from_ref(state); | ||
|
||
// Retrieve user information based on the API key from the database. | ||
let user = users::Model::find_by_api_key(&state.db, &api_key).await?; | ||
|
||
Ok(Self { user }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod api_key; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod auth; | ||
pub mod middleware; | ||
pub mod notes; | ||
pub mod user; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,22 @@ | ||
use loco_rs::prelude::*; | ||
|
||
use crate::controllers::middleware::api_key::ApiToken; | ||
use crate::{models::_entities::users, views::user::CurrentResponse}; | ||
use loco_rs::prelude::*; | ||
|
||
async fn current(auth: auth::JWT, State(ctx): State<AppContext>) -> Result<Json<CurrentResponse>> { | ||
let user = users::Model::find_by_pid(&ctx.db, &auth.claims.pid).await?; | ||
format::json(CurrentResponse::new(&user)) | ||
} | ||
|
||
async fn current_by_api_key( | ||
auth: ApiToken, | ||
State(_ctx): State<AppContext>, | ||
) -> Result<Json<CurrentResponse>> { | ||
format::json(CurrentResponse::new(&auth.user)) | ||
} | ||
|
||
pub fn routes() -> Routes { | ||
Routes::new().prefix("user").add("/current", get(current)) | ||
Routes::new() | ||
.prefix("user") | ||
.add("/current", get(current)) | ||
.add("/current_api_key", get(current_by_api_key)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,15 @@ | |
pid: 11111111-1111-1111-1111-111111111111 | ||
email: [email protected] | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$ETQBx4rTgNAZhSaeYZKOZg$eYTdH26CRT6nUJtacLDEboP0li6xUwUF/q5nSlQ8uuc" | ||
api_key: lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758 | ||
name: user1 | ||
created_at: "2023-11-12T12:34:56.789" | ||
updated_at: "2023-11-12T12:34:56.789" | ||
- id: 2 | ||
pid: 22222222-2222-2222-2222-222222222222 | ||
email: [email protected] | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$ETQBx4rTgNAZhSaeYZKOZg$eYTdH26CRT6nUJtacLDEboP0li6xUwUF/q5nSlQ8uuc" | ||
api_key: lo-153561ca-fa84-4e1b-813a-c62526d0a77e | ||
name: user2 | ||
created_at: "2023-11-12T12:34:56.789" | ||
updated_at: "2023-11-12T12:34:56.789" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: PID, | ||
email: "[email protected]", | ||
password: "PASSWORD", | ||
api_key: "lo-PID", | ||
name: "framework", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: 11111111-1111-1111-1111-111111111111, | ||
email: "[email protected]", | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$ETQBx4rTgNAZhSaeYZKOZg$eYTdH26CRT6nUJtacLDEboP0li6xUwUF/q5nSlQ8uuc", | ||
api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", | ||
name: "user1", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ok( | |
pid: 11111111-1111-1111-1111-111111111111, | ||
email: "[email protected]", | ||
password: "$argon2id$v=19$m=19456,t=2,p=1$ETQBx4rTgNAZhSaeYZKOZg$eYTdH26CRT6nUJtacLDEboP0li6xUwUF/q5nSlQ8uuc", | ||
api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", | ||
name: "user1", | ||
reset_token: None, | ||
reset_sent_at: None, | ||
|
8 changes: 8 additions & 0 deletions
8
...ers/rest-api/tests/requests/snapshots/can_get_current_user_with_api_key@user_request.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
source: tests/requests/user.rs | ||
expression: "(response.status_code(), response.text())" | ||
--- | ||
( | ||
200, | ||
"{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"[email protected]\"}", | ||
) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering,
how possible is it to say:
and we know that T should eventually be users::Model,
maybe this T will be a
T: Trait
whereT: FetchByApiKey
,and the
User impl
that FetchByApiKey.Now this middleware becomes shareable by everyone
PS: i think we can adopt the same pattern for the JWT auth by creating a trait
T: FetchByJWT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API token is generated within the user app (Loco framework is not familiar with that). In this scenario, I think the parameter is meaningless, as the user has complete control over it.
About the FetchByJWT i totally agree. maybe we can consider moving the claims to be a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice what I did in the latest commit. I had a feeling if we move things around we might get something, I think it worked:
Authenticable
trait lets us encapsulate all the logic, and then -- just refer to an extractor. UseApiToken<T>
andApiToken<users::Model>
to give Rust all the type information it needs to resolve.On this "Authenticable" concept we can also encode the
JWT
behavior, and "capture" a user just like in api key auth.There is a good chance that instead of having claims we can have the actual user model if we use the same trick.