Skip to content

Commit

Permalink
Implement authentication
Browse files Browse the repository at this point in the history
Authenticate the user when they register, by encoding their ID into a
JWT.

Currently the signing secret is a constant in source code - before this
is production ready, we should generate a random application-wide token
on startup.

Since the cookie crate uses time instead of chrono, we now have two time
crates. At some point we should attempt to only use one.
  • Loading branch information
Aleksbgbg committed Feb 8, 2024
1 parent 253377c commit f1be96c
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 25 deletions.
2 changes: 2 additions & 0 deletions backend-rs/.env.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[config.app]
host = [0, 0, 0, 0]
port = 8601
# Half a year, in seconds
token_lifespan = 15724800

[config.database]
host = [127, 0, 0, 1]
Expand Down
170 changes: 167 additions & 3 deletions backend-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions backend-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ edition = "2021"

[dependencies]
axum = "0.7.4"
axum-extra = { version = "0.9.2", features = ["cookie"] }
bcrypt = "0.15.0"
bs58 = "0.5.0"
chrono = "0.4.33"
convert_case = "0.6.0"
jsonwebtoken = { version = "9.2.0", default-features = false }
lazy_static = "1.4.0"
rs-snowflake = "0.6.0"
sea-orm = { version = "0.12.14", features = ["runtime-tokio-native-tls", "sqlx-postgres"] }
sea-orm-migration = "0.12.12"
serde = { version = "1.0.196", features = ["derive"] }
serde_json = "1.0.113"
serde_with = { version = "3.6.0", features = ["chrono_0_4"] }
thiserror = "1.0.56"
time = "0.3.34"
tokio = { version = "1.36.0", features = ["rt-multi-thread"] }
toml-env = "1.1.1"
tower-http = { version = "0.5.1", features = ["trace"] }
Expand Down
3 changes: 3 additions & 0 deletions backend-rs/src/app_state.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::config::Config;
use sea_orm::DatabaseConnection;
use snowflake::SnowflakeIdBucket;
use std::sync::Arc;

#[derive(Clone)]
pub struct AppState {
pub config: Arc<Config>,
pub connection: DatabaseConnection,
pub user_snowflake: SnowflakeIdBucket,
}
5 changes: 5 additions & 0 deletions backend-rs/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use chrono::Duration;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DurationSeconds};
use thiserror::Error;
use toml_env::Args;

Expand All @@ -15,10 +17,13 @@ pub struct Config {
pub database: Database,
}

#[serde_as]
#[derive(Serialize, Deserialize)]
pub struct App {
pub host: Ipv4Array,
pub port: Port,
#[serde_as(as = "DurationSeconds<i64>")]
pub token_lifespan: Duration,
}

#[derive(Serialize, Deserialize)]
Expand Down
4 changes: 4 additions & 0 deletions backend-rs/src/controllers/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::controllers::user::AuthError;
use crate::models::user;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
Expand Down Expand Up @@ -56,6 +57,8 @@ pub enum HandlerError {
Database(#[from] DbErr),
#[error("Could not create user.")]
CreateUser(#[from] user::CreateError),
#[error("Could not authenticate: {0}.")]
Authenticate(#[from] AuthError),
}

impl HandlerError {
Expand All @@ -77,6 +80,7 @@ impl IntoResponse for HandlerError {
HandlerError::EmailTaken => self.failed_validation(StatusCode::BAD_REQUEST, "emailAddress"),
HandlerError::Database(_) => self.into_generic(StatusCode::INTERNAL_SERVER_ERROR),
HandlerError::CreateUser(_) => self.into_generic(StatusCode::INTERNAL_SERVER_ERROR),
HandlerError::Authenticate(_) => self.into_generic(StatusCode::INTERNAL_SERVER_ERROR),
}
.into_response()
}
Expand Down
Loading

0 comments on commit f1be96c

Please sign in to comment.