Skip to content

Commit beedaf3

Browse files
MacKarpdavidgraeff
authored andcommitted
Added user session by OAuth2 Federated provider
I have added user seession by OAuth2 Federated provider. List of defualt providers are at: https://firebase.google.com/docs/projects/provisioning/configure-oauth?hl=en#add-idp Code is implementing this endpoint: https://firebase.google.com/docs/reference/rest/auth?hl=en#section-sign-in-with-oauth-credential it's better version of my code that I have written for my university project, where I only used it for Google and Facebook OAuth2: https://github.com/MacKarp/Cookbook/tree/main/Desktop/firebase_handler/src `access_token` from provider - eg. https://docs.rs/oauth2/4.0.0/oauth2/#example-3 `provider` from enum `OAuth2Provider` `request_uri` should be same as your request_uri/redirect_uri for provider request `with_refresh_token` - needed by `by_user_id` after getting response from firebase it creates user session with exisisting `Session::by_user_id` Signed-off-by: Karpfly <[email protected]>
1 parent d7d3e45 commit beedaf3

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

src/dto.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,34 @@ pub struct WriteRequest {
547547
pub stream_id: Option<String>,
548548
}
549549

550+
#[derive(Serialize, Debug)]
551+
pub struct SignInWithIdpRequest {
552+
pub post_body: String,
553+
pub request_uri: String,
554+
pub return_idp_credential: bool,
555+
pub return_secure_token: bool,
556+
}
557+
558+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
559+
#[serde(rename_all = "camelCase")]
560+
pub struct OAuthResponse {
561+
pub federated_id: String,
562+
pub provider_id: String,
563+
pub local_id: String,
564+
pub email_verified: bool,
565+
pub email: String,
566+
pub oauth_access_token: String,
567+
pub first_name: String,
568+
pub last_name: String,
569+
pub full_name: String,
570+
pub display_name: String,
571+
pub id_token: String,
572+
pub photo_url: String,
573+
pub refresh_token: String,
574+
pub expires_in: String,
575+
pub raw_user_info: String,
576+
}
577+
550578
#[cfg(test)]
551579
mod tests {
552580
#[test]

src/sessions.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::slice::Iter;
1818

1919
pub mod user {
2020
use super::*;
21+
use crate::dto::{OAuthResponse, SignInWithIdpRequest};
2122
use credentials::Credentials;
2223

2324
#[inline]
@@ -33,6 +34,36 @@ pub mod user {
3334
format!("https://securetoken.googleapis.com/v1/token?key={}", v)
3435
}
3536

37+
/// Default OAuth2 Providers supported by Firebase.
38+
/// see: * https://firebase.google.com/docs/projects/provisioning/configure-oauth?hl=en#add-idp
39+
pub enum OAuth2Provider {
40+
Apple,
41+
AppleGameCenter,
42+
Facebook,
43+
GitHub,
44+
Google,
45+
GooglePlayGames,
46+
LinkedIn,
47+
Microsoft,
48+
Twitter,
49+
Yahoo,
50+
}
51+
52+
fn get_provider(provider: OAuth2Provider) -> String {
53+
match provider {
54+
OAuth2Provider::Apple => "apple.com".to_string(),
55+
OAuth2Provider::AppleGameCenter => "gc.apple.com".to_string(),
56+
OAuth2Provider::Facebook => "facebook.com".to_string(),
57+
OAuth2Provider::GitHub => "github.com".to_string(),
58+
OAuth2Provider::Google => "google.com".to_string(),
59+
OAuth2Provider::GooglePlayGames => "playgames.google.com".to_string(),
60+
OAuth2Provider::LinkedIn => "linkedin.com".to_string(),
61+
OAuth2Provider::Microsoft => "microsoft.com".to_string(),
62+
OAuth2Provider::Twitter => "twitter.com".to_string(),
63+
OAuth2Provider::Yahoo => "yahoo.com".to_string(),
64+
}
65+
}
66+
3667
/// An impersonated session.
3768
/// Firestore rules will restrict your access.
3869
pub struct Session {
@@ -281,6 +312,46 @@ pub mod user {
281312
client_async: reqwest::Client::new(),
282313
})
283314
}
315+
316+
/// Creates a new user session with OAuth2 provider token.
317+
/// If user don't exist it's create new user in firestore
318+
///
319+
/// Arguments:
320+
/// - `credentials` The credentials.
321+
/// - `access_token` access_token provided by OAuth2 provider.
322+
/// - `request_uri` The URI to which the provider redirects the user back same as from .
323+
/// - `provider` OAuth2Provider enum: Apple, AppleGameCenter, Facebook, GitHub, Google, GooglePlayGames, LinkedIn, Microsoft, Twitter, Yahoo.
324+
/// - `with_refresh_token` A refresh token is returned as well. This should be persisted somewhere for later reuse.
325+
/// Google generates only a few dozens of refresh tokens before it starts to invalidate already generated ones.
326+
/// For short lived, immutable, non-persisting services you do not want a refresh token.
327+
///
328+
pub fn by_oauth2(
329+
credentials: &Credentials,
330+
access_token: String,
331+
provider: OAuth2Provider,
332+
request_uri: String,
333+
with_refresh_token: bool,
334+
) -> Result<Session, FirebaseError> {
335+
let uri = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key=".to_owned()
336+
+ &credentials.api_key;
337+
338+
let post_body = format!("access_token={}&providerId={}", access_token, get_provider(provider));
339+
let return_idp_credential = true;
340+
let return_secure_token = true;
341+
342+
let json = &SignInWithIdpRequest {
343+
post_body,
344+
request_uri,
345+
return_idp_credential,
346+
return_secure_token,
347+
};
348+
349+
let response = reqwest::blocking::Client::new().post(&uri).json(&json).send()?;
350+
351+
let oauth_response: OAuthResponse = response.json()?;
352+
353+
self::Session::by_user_id(&credentials, &oauth_response.local_id, with_refresh_token)
354+
}
284355
}
285356
}
286357

0 commit comments

Comments
 (0)