I want to use third-party authentication #557
Replies: 3 comments
-
We have a token auth strategy now: all you need is to write the connect logic to put a firebase token there when you need it |
Beta Was this translation helpful? Give feedback.
-
Thanks so much for the tip!👍 auth: auth::ApiToken<users::Model>, When I looked at the contents of this, it looked like this: // 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 = 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 = T::find_by_api_key(&state.db, &api_key)
.await
.map_err(|e| Error::Unauthorized(e.to_string()))?;
Ok(Self { user })
} This connects the Bearer token received in the header to the DB, With this, I feel like I can't do what I want to do. https://firebase.google.com/docs/auth/admin/verify-id-tokens?hl=en#verify_id_tokens_using_a_third-party_jwt_library And I want to use User.find_by_uid with the uid that can be verified and obtained when successful. ref: https://firebase.google.com/docs/auth/android/manage-users?hl=ja#get_a_users_profile Sorry for all the things I wanted to ask! I would really appreciate it if you could let me know if there is a way to accomplish this.😄 |
Beta Was this translation helpful? Give feedback.
-
Try various things, use async_trait::async_trait;
use axum::{
extract::{FromRef, FromRequestParts},
http::{request::Parts, HeaderMap},
};
use firebase_auth::{FirebaseAuth, FirebaseAuthState, FirebaseUser};
use loco_rs::app::AppContext;
use loco_rs::errors::Error;
use loco_rs::model::Authenticable;
use serde::{Deserialize, Serialize};
// Define constants for token prefix and authorization header
const TOKEN_PREFIX: &str = "Bearer ";
const AUTH_HEADER: &str = "authorization";
#[derive(Debug, Deserialize, Serialize)]
// Represents the data structure for the API token.
pub struct FirebaseToken<T: Authenticable> {
pub user: T,
}
/// Function to extract a token from the authorization header
///
/// # Errors
///
/// When token is not valid or out found
pub fn extract_token_from_header(headers: &HeaderMap) -> eyre::Result<String> {
Ok(headers
.get(AUTH_HEADER)
.ok_or_else(|| eyre::eyre!("header {} token not found", AUTH_HEADER))?
.to_str()?
.strip_prefix(TOKEN_PREFIX)
.ok_or_else(|| eyre::eyre!("error strip {} value", AUTH_HEADER))?
.to_string())
}
#[async_trait]
impl<S, T> FromRequestParts<S> for FirebaseToken<T>
where
AppContext: FromRef<S>,
S: Send + Sync,
T: Authenticable,
{
type Rejection = Error;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Error> {
// Extract API key from the request header.
let token = extract_token_from_header(&parts.headers)
.map_err(|e| Error::Unauthorized(e.to_string()))?;
let firebase_auth = FirebaseAuth::new("knight-navi-dev").await;
let firebase_auth_state = FirebaseAuthState::new(firebase_auth);
match firebase_auth_state
.firebase_auth
.verify::<FirebaseUser>(&token)
{
Err(e) => Err(Error::Unauthorized(e.to_string())),
Ok(current_user) => {
let state: AppContext = AppContext::from_ref(state);
let user = T::find_by_api_key(&state.db, ¤t_user.user_id)
.await
.map_err(|e| Error::Unauthorized(e.to_string()))?;
Ok(Self { user })
}
}
}
} and pub(crate) use crate::{models::_entities::users, views::user::CurrentResponse};
use loco_rs::prelude::*;
use super::middleware::custom_auth;
async fn current(
auth: custom_auth::FirebaseToken<users::Model>,
State(_ctx): State<AppContext>,
) -> Result<Response> {
format::json(CurrentResponse::new(&auth.user))
}
pub fn routes() -> Routes {
Routes::new().prefix("user").add("/current", get(current))
} |
Beta Was this translation helpful? Give feedback.
-
Thank you for creating such an interesting framework!
i make project by Rest Api mode.
but I want to use firebase authentication
(senf from frontend Bearer 〇〇←firebase token)
How can I change the authentication logic?
and, If I were to be greedy, I would like to be able to get an authenticated user from each controller,
similar to Rails' application_controller::current_user this firebase authenticated user
Sorry for my poor English
I look forward to receiving your tips.
Beta Was this translation helpful? Give feedback.
All reactions