Skip to content

Commit

Permalink
feat(user): add single purpose token and auth (#4470)
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorvdixit88 committed Apr 29, 2024
1 parent ac9d856 commit c20ecb8
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 2 deletions.
2 changes: 2 additions & 0 deletions crates/router/src/consts.rs
Expand Up @@ -68,6 +68,8 @@ pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes

pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days

pub const SINGLE_PURPOSE_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day

pub const JWT_TOKEN_COOKIE_NAME: &str = "login_token";

pub const USER_BLACKLIST_PREFIX: &str = "BU_";
Expand Down
82 changes: 81 additions & 1 deletion crates/router/src/services/authentication.rs
Expand Up @@ -64,6 +64,10 @@ pub enum AuthenticationType {
UserJwt {
user_id: String,
},
SinglePurposeJWT {
user_id: String,
purpose: Purpose,
},
MerchantId {
merchant_id: String,
},
Expand Down Expand Up @@ -101,11 +105,51 @@ impl AuthenticationType {
user_id: _,
}
| Self::WebhookAuth { merchant_id } => Some(merchant_id.as_ref()),
Self::AdminApiKey | Self::UserJwt { .. } | Self::NoAuth => None,
Self::AdminApiKey
| Self::UserJwt { .. }
| Self::SinglePurposeJWT { .. }
| Self::NoAuth => None,
}
}
}

#[derive(Clone, Debug)]
pub struct UserFromSinglePurposeToken {
pub user_id: String,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct SinglePurposeToken {
pub user_id: String,
pub purpose: Purpose,
pub exp: u64,
}

#[derive(Debug, Clone, PartialEq, Eq, strum::Display, serde::Deserialize, serde::Serialize)]
pub enum Purpose {
AcceptInvite,
}

#[cfg(feature = "olap")]
impl SinglePurposeToken {
pub async fn new_token(
user_id: String,
purpose: Purpose,
settings: &Settings,
) -> UserResult<String> {
let exp_duration =
std::time::Duration::from_secs(consts::SINGLE_PURPOSE_TOKEN_TIME_IN_SECS);
let exp = jwt::generate_exp(exp_duration)?.as_secs();
let token_payload = Self {
user_id,
purpose,
exp,
};
jwt::generate_jwt(&token_payload, settings).await
}
}

// TODO: This has to be removed once single purpose token is used as a intermediate token
#[derive(Clone, Debug)]
pub struct UserWithoutMerchantFromToken {
pub user_id: String,
Expand Down Expand Up @@ -316,6 +360,42 @@ where
}
}

#[allow(dead_code)]
#[derive(Debug)]
pub(crate) struct SinglePurposeJWTAuth(pub Purpose);

#[cfg(feature = "olap")]
#[async_trait]
impl<A> AuthenticateAndFetch<UserFromSinglePurposeToken, A> for SinglePurposeJWTAuth
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(UserFromSinglePurposeToken, AuthenticationType)> {
let payload = parse_jwt_payload::<A, SinglePurposeToken>(request_headers, state).await?;
if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}

if self.0 != payload.purpose {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}

Ok((
UserFromSinglePurposeToken {
user_id: payload.user_id.clone(),
},
AuthenticationType::SinglePurposeJWT {
user_id: payload.user_id,
purpose: payload.purpose,
},
))
}
}

#[derive(Debug)]
pub struct AdminApiAuth;

Expand Down
12 changes: 11 additions & 1 deletion crates/router/src/services/authentication/blacklist.rs
Expand Up @@ -5,7 +5,7 @@ use common_utils::date_time;
use error_stack::ResultExt;
use redis_interface::RedisConnectionPool;

use super::{AuthToken, UserAuthToken};
use super::{AuthToken, SinglePurposeToken, UserAuthToken};
#[cfg(feature = "email")]
use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS};
use crate::{
Expand Down Expand Up @@ -163,3 +163,13 @@ impl BlackList for UserAuthToken {
check_user_in_blacklist(state, &self.user_id, self.exp).await
}
}

#[async_trait::async_trait]
impl BlackList for SinglePurposeToken {
async fn check_in_blacklist<A>(&self, state: &A) -> RouterResult<bool>
where
A: AppStateInfo + Sync,
{
check_user_in_blacklist(state, &self.user_id, self.exp).await
}
}

0 comments on commit c20ecb8

Please sign in to comment.