Bug: feat: Add cookie parsing



Parse cookie header to get JWT. Compare with the JWT retrieved from `Authorization` header and log the result. 
diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs
index 0181ec4e799..a7c54ef8f34 100644
--- a/crates/router/src/compatibility/stripe/errors.rs
+++ b/crates/router/src/compatibility/stripe/errors.rs
@@ -427,6 +427,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
             | errors::ApiErrorResponse::InvalidJwtToken
             | errors::ApiErrorResponse::GenericUnauthorized { .. }
             | errors::ApiErrorResponse::AccessForbidden { .. }
+            | errors::ApiErrorResponse::InvalidCookie
             | errors::ApiErrorResponse::InvalidEphemeralKey => Self::Unauthorized,
             errors::ApiErrorResponse::InvalidRequestUrl
             | errors::ApiErrorResponse::InvalidHttpMethod
diff --git a/crates/router/src/core/errors/api_error_response.rs b/crates/router/src/core/errors/api_error_response.rs
index b3fbbaaf141..dc3e19cb725 100644
--- a/crates/router/src/core/errors/api_error_response.rs
+++ b/crates/router/src/core/errors/api_error_response.rs
@@ -260,6 +260,11 @@ pub enum ApiErrorResponse {
     CurrencyConversionFailed,
     #[error(error_type = ErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
     PaymentMethodDeleteFailed,
+    #[error(
+        error_type = ErrorType::InvalidRequestError, code = "IR_26",
+        message = "Invalid Cookie"
+    )]
+    InvalidCookie,
 }
 
 impl PTError for ApiErrorResponse {
diff --git a/crates/router/src/core/errors/transformers.rs b/crates/router/src/core/errors/transformers.rs
index 110feb22df3..7c06fc92c99 100644
--- a/crates/router/src/core/errors/transformers.rs
+++ b/crates/router/src/core/errors/transformers.rs
@@ -292,6 +292,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
             Self::PaymentMethodDeleteFailed => {
                 AER::BadRequest(ApiError::new("IR", 25, "Cannot delete the default payment method", None))
             }
+            Self::InvalidCookie => {
+                AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
+            }
         }
     }
 }
diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs
index d2247150d3c..f7acbe6f933 100644
--- a/crates/router/src/services/authentication.rs
+++ b/crates/router/src/services/authentication.rs
@@ -5,6 +5,7 @@ use common_utils::date_time;
 use error_stack::{report, ResultExt};
 use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
 use masking::PeekInterface;
+use router_env::logger;
 use serde::Serialize;
 
 use self::blacklist::BlackList;
@@ -33,7 +34,6 @@ use crate::{
     utils::OptionExt,
 };
 pub mod blacklist;
-#[cfg(feature = "olap")]
 pub mod cookies;
 
 #[derive(Clone, Debug)]
@@ -598,6 +598,15 @@ where
     A: AppStateInfo + Sync,
 {
     let token = get_jwt_from_authorization_header(headers)?;
+    if let Some(token_from_cookies) = get_cookie_from_header(headers)
+        .ok()
+        .and_then(|cookies| cookies::parse_cookie(cookies).ok())
+    {
+        logger::info!(
+            "Cookie header and authorization header JWT comparison result: {}",
+            token == token_from_cookies
+        );
+    }
     let payload = decode_jwt(token, state).await?;
 
     Ok(payload)
@@ -959,6 +968,13 @@ pub fn get_jwt_from_authorization_header(headers: &HeaderMap) -> RouterResult<&s
         .ok_or(errors::ApiErrorResponse::InvalidJwtToken.into())
 }
 
+pub fn get_cookie_from_header(headers: &HeaderMap) -> RouterResult<&str> {
+    headers
+        .get(cookies::get_cookie_header())
+        .and_then(|header_value| header_value.to_str().ok())
+        .ok_or(errors::ApiErrorResponse::InvalidCookie.into())
+}
+
 pub fn strip_jwt_token(token: &str) -> RouterResult<&str> {
     token
         .strip_prefix("Bearer ")
diff --git a/crates/router/src/services/authentication/cookies.rs b/crates/router/src/services/authentication/cookies.rs
index d7fc4c10315..96518840800 100644
--- a/crates/router/src/services/authentication/cookies.rs
+++ b/crates/router/src/services/authentication/cookies.rs
@@ -1,15 +1,27 @@
+use cookie::Cookie;
+#[cfg(feature = "olap")]
 use cookie::{
     time::{Duration, OffsetDateTime},
-    Cookie, SameSite,
+    SameSite,
 };
-use masking::{ExposeInterface, Mask, Secret};
+use error_stack::{report, ResultExt};
+#[cfg(feature = "olap")]
+use masking::Mask;
+#[cfg(feature = "olap")]
+use masking::{ExposeInterface, Secret};
 
 use crate::{
-    consts::{JWT_TOKEN_COOKIE_NAME, JWT_TOKEN_TIME_IN_SECS},
+    consts::JWT_TOKEN_COOKIE_NAME,
+    core::errors::{ApiErrorResponse, RouterResult},
+};
+#[cfg(feature = "olap")]
+use crate::{
+    consts::JWT_TOKEN_TIME_IN_SECS,
     core::errors::{UserErrors, UserResponse},
     services::ApplicationResponse,
 };
 
+#[cfg(feature = "olap")]
 pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserResponse<R> {
     let jwt_expiry_in_seconds = JWT_TOKEN_TIME_IN_SECS
         .try_into()
@@ -19,16 +31,17 @@ pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserRespons
     let header_value = create_cookie(token, expiry, max_age)
         .to_string()
         .into_masked();
-    let header_key = get_cookie_header();
+    let header_key = get_set_cookie_header();
     let header = vec![(header_key, header_value)];
 
     Ok(ApplicationResponse::JsonWithHeaders((response, header)))
 }
 
+#[cfg(feature = "olap")]
 pub fn remove_cookie_response() -> UserResponse<()> {
     let (expiry, max_age) = get_expiry_and_max_age_from_seconds(0);
 
-    let header_key = get_cookie_header();
+    let header_key = get_set_cookie_header();
     let header_value = create_cookie("".to_string().into(), expiry, max_age)
         .to_string()
         .into_masked();
@@ -36,6 +49,19 @@ pub fn remove_cookie_response() -> UserResponse<()> {
     Ok(ApplicationResponse::JsonWithHeaders(((), header)))
 }
 
+pub fn parse_cookie(cookies: &str) -> RouterResult<String> {
+    Cookie::split_parse(cookies)
+        .find_map(|cookie| {
+            cookie
+                .ok()
+                .filter(|parsed_cookie| parsed_cookie.name() == JWT_TOKEN_COOKIE_NAME)
+                .map(|parsed_cookie| parsed_cookie.value().to_owned())
+        })
+        .ok_or(report!(ApiErrorResponse::InvalidCookie))
+        .attach_printable("Cookie Parsing Failed")
+}
+
+#[cfg(feature = "olap")]
 fn create_cookie<'c>(
     token: Secret<String>,
     expires: OffsetDateTime,
@@ -51,12 +77,18 @@ fn create_cookie<'c>(
         .build()
 }
 
+#[cfg(feature = "olap")]
 fn get_expiry_and_max_age_from_seconds(seconds: i64) -> (OffsetDateTime, Duration) {
     let max_age = Duration::seconds(seconds);
     let expiry = OffsetDateTime::now_utc().saturating_add(max_age);
     (expiry, max_age)
 }
 
-fn get_cookie_header() -> String {
+#[cfg(feature = "olap")]
+fn get_set_cookie_header() -> String {
     actix_http::header::SET_COOKIE.to_string()
 }
+
+pub fn get_cookie_header() -> String {
+    actix_http::header::COOKIE.to_string()
+}

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [X] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
This is the second PR for cookie implementation.
In this PR, cookie header is parsed to retrieve JWT that was set during dashboard entry.
This PR does not remove old auth flow where `Authorization` header was used to retrieve JWT from request. Instead, it compares  the JWT retrieved from `Authorization` header and `Cookie` header and logs the result. 
<!-- Describe your changes in detail -->


### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
Storing JWT in cookies instead of local storage.
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
No testing required, feature is not complete and hence is not enabled.
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [X] I formatted the code `cargo +nightly fmt --all`
- [X] I addressed lints thrown by `cargo clippy`
- [X] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
