diff --git a/Cargo.lock b/Cargo.lock index 0c23d64..8609474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -501,7 +501,13 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627" dependencies = [ + "aes-gcm", + "base64 0.13.0", + "hkdf", "percent-encoding", + "rand 0.8.3", + "sha2", + "subtle", "time 0.2.26", "version_check", ] @@ -1265,6 +1271,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "hmac" version = "0.10.1" diff --git a/api/Cargo.toml b/api/Cargo.toml index b9e7248..fbfc0ea 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -15,5 +15,5 @@ serde = {version = "1.0", features = ["derive"] } tenebrous-rpc = { path = "../rpc" } juniper = { git = "https://github.com/graphql-rust/juniper", branch = "master" } juniper_rocket_async = { git = "https://github.com/graphql-rust/juniper", branch = "master" } -rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["json"] } +rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["json", "secrets"] } rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" } diff --git a/api/src/auth.rs b/api/src/auth.rs index a6c7f44..f24b0d0 100644 --- a/api/src/auth.rs +++ b/api/src/auth.rs @@ -1,6 +1,7 @@ use crate::config::Config; use chrono::{Duration, Utc}; use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; +use rocket::http::{Cookie, CookieJar}; use rocket::response::status::Custom; use rocket::{ http::Status, @@ -25,27 +26,40 @@ struct LoginRequest<'a> { password: &'a str, } -#[rocket::post("/login", data = "")] -async fn login<'a>( - request: Json>, - config: &State, +fn create_token<'a>( + username: &str, + expiration: Duration, + secret: &str, ) -> Result> { let expiration = Utc::now() - .checked_add_signed(Duration::seconds(60)) + .checked_add_signed(expiration) .expect("clock went awry") .timestamp(); let claims = Claims { exp: expiration as usize, - sub: request.username.to_owned(), + sub: username.to_owned(), }; let token = encode( &Header::default(), &claims, - &EncodingKey::from_secret(config.jwt_secret.as_ref()), + &EncodingKey::from_secret(secret.as_bytes()), ) .map_err(|e| Custom(Status::InternalServerError, e.to_string()))?; Ok(token) } + +#[rocket::post("/login", data = "")] +async fn login( + request: Json>, + config: &State, + cookies: &CookieJar<'_>, +) -> Result> { + let token = create_token(request.username, Duration::minutes(1), &config.jwt_secret)?; + let refresh_token = create_token(request.username, Duration::weeks(1), &config.jwt_secret)?; + + cookies.add_private(Cookie::new("refresh_token", refresh_token)); + Ok(token) +}