Skip to content
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

feat(session): add create session cookie feature #13

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ chrono = { version = "0.4", features = ["serde"] }
biscuit = "0.5"
ring = "0.16"
base64 = "0.13"
jsonwebtoken = "7"

[dependencies.rocket]
version = "0.4.6"
Expand Down
87 changes: 87 additions & 0 deletions src/sessions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use std::slice::Iter;
pub mod user {
use super::*;
use credentials::Credentials;
use std::time::{SystemTime, UNIX_EPOCH};
use jsonwebtoken::{Algorithm, encode, EncodingKey, Header};

#[inline]
fn token_endpoint(v: &str) -> String {
Expand Down Expand Up @@ -138,6 +140,40 @@ pub mod user {
project_id: String,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[allow(non_snake_case)]
struct SessionLogin {
idToken: String,
validDuration: u64,
}

#[derive(Debug, Deserialize)]
struct Oauth2Response {
access_token: String,
expires_in: u64,
token_type: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
scope: String,
aud: String,
exp: u64,
iat: u64,
iss: String,
}

#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct CreateSessionCookieResponseJson {
sessionCookie: String,
}

#[derive(Debug, Deserialize)]
pub struct CreateSessionCookie {
pub session_cookie: String,
}

impl Session {
/// Create an impersonated session
///
Expand Down Expand Up @@ -270,6 +306,57 @@ pub mod user {
client_async: reqwest::Client::new(),
})
}

pub fn create_session_cookie(credentials: &Credentials, id_token: String, duration: u64) -> Result<CreateSessionCookie, FirebaseError> {
let scope_list = vec![
"https://www.googleapis.com/auth/cloud-platform".to_string(),
"https://www.googleapis.com/auth/firebase.database".to_string(),
"https://www.googleapis.com/auth/firebase.messaging".to_string(),
"https://www.googleapis.com/auth/identitytoolkit".to_string(),
"https://www.googleapis.com/auth/userinfo.email".to_string(),
];

// Generate the assertion from the admin credentials
let iat = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let assertion = encode(&Header::new(Algorithm::RS256),
&Claims {
scope: scope_list.join(" "),
aud: "https://accounts.google.com/o/oauth2/token".to_string(),
iat,
exp : iat + duration,
iss: credentials.client_email.to_string(),
},
&EncodingKey::from_rsa_pem(credentials.private_key.to_string().as_ref()).unwrap())
.unwrap();

// Request Google Oauth2 to retrieve the access token in order to create a session cookie
let client = reqwest::blocking::Client::new();
let google_oauth2_url = "https://accounts.google.com/o/oauth2/token".to_string();
let response_oauth2: Oauth2Response = client.post(&google_oauth2_url)
.form(&[("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), ("assertion", &assertion)])
.send()
.unwrap()
.json()
.unwrap();

// Create a session cookie with the access token previously retrieved
let create_session_cookie_url: String = "https://identitytoolkit.googleapis.com/v1/projects/arenel:createSessionCookie".to_string();
let response_session_cookie_json: CreateSessionCookieResponseJson = client.post(&create_session_cookie_url)
.bearer_auth(&response_oauth2.access_token)
.json(&SessionLogin {
idToken: id_token,
validDuration: duration,
})
.send()
.unwrap()
.json()
.unwrap();


Ok(CreateSessionCookie {
session_cookie : response_session_cookie_json.sessionCookie
})
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions tests/sessions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use firestore_db_and_auth::*;
use firestore_db_and_auth::sessions::user::Session;
use std::fs;

#[test]
fn user_session_create_session_cookie() -> errors::Result<()> {
let cred = credentials::Credentials::from_file("firebase-service-account.json").expect("Read credentials file");
let id_token: String = fs::read_to_string("refresh-token-for-tests.txt")?;

println!("users::Session::create_session_cookie");
Session::create_session_cookie(&cred, id_token.to_string(), 3600)?;

Ok(())
}