Skip to content

Commit e24c8ea

Browse files
committed
security fixes
1 parent 38cd06d commit e24c8ea

16 files changed

Lines changed: 420 additions & 49 deletions

‎.claude/skills/audit-security/SKILL.md‎

Lines changed: 298 additions & 0 deletions
Large diffs are not rendered by default.

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
.env.*
66
!.env.example
77
.claude/settings.local.json
8+
.sqlx

‎.sqlx/query-d2a9875d4953ff4c1ffd3787cde06425641dc7166ba8812cc77ff0addbe1e9dd.json‎

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎Cargo.lock‎

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[workspace]
2+
members = ["xtask"]
3+
14
[package]
25
name = "beyond-auth"
36
version = "0.1.0"

‎migrations/0002_authn.sql‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ SET search_path = auth, public;
44

55
ALTER TABLE auth.app_config
66
ADD COLUMN jwt_enabled bool NOT NULL DEFAULT false,
7-
ADD COLUMN issuer_url text;
7+
ADD COLUMN issuer_url text,
8+
ADD COLUMN jwt_audience text;
89

910
-- Tenants: personal (1:1 with user, created atomically on signup) and team tenants (Phase 3+)
1011

‎mise.toml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ yamlfmt = "latest"
66

77
[tasks."format"]
88
run = "dprint fmt"
9+
10+
[tasks."sqlx:prepare"]
11+
run = "cargo run --package xtask"

‎src/app_config.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ pub struct AppConfig {
1010
pub session_ttl_seconds: i32,
1111
pub jwt_enabled: bool,
1212
pub issuer_url: Option<String>,
13+
pub jwt_audience: Option<String>,
1314
}
1415

1516
pub async fn load(pool: &PgPool) -> Result<AppConfig, AuthError> {
1617
sqlx::query_as!(
1718
AppConfig,
18-
"SELECT jwt_mode, access_token_ttl_seconds, session_ttl_seconds, jwt_enabled, issuer_url
19+
"SELECT jwt_mode, access_token_ttl_seconds, session_ttl_seconds, jwt_enabled, issuer_url, jwt_audience
1920
FROM auth.app_config
2021
WHERE id = true"
2122
)

‎src/error.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pub enum AuthError {
2525
#[error("password must be at least 8 characters")]
2626
PasswordTooShort,
2727

28+
#[error("password must be at most 128 characters")]
29+
PasswordTooLong,
30+
2831
#[error("password is too common")]
2932
PasswordTooCommon,
3033

@@ -95,6 +98,9 @@ impl IntoResponse for AuthError {
9598
AuthError::PasswordTooShort => {
9699
(StatusCode::UNPROCESSABLE_ENTITY, "password_too_short", self.to_string())
97100
}
101+
AuthError::PasswordTooLong => {
102+
(StatusCode::UNPROCESSABLE_ENTITY, "password_too_long", self.to_string())
103+
}
98104
AuthError::PasswordTooCommon => {
99105
(StatusCode::UNPROCESSABLE_ENTITY, "password_too_common", self.to_string())
100106
}

‎src/jwt.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::error::AuthError;
99
pub fn issue_access_token(
1010
user_id: Uuid,
1111
issuer_url: &str,
12+
audience: &str,
1213
ttl_seconds: i32,
1314
kid: Uuid,
1415
signing_key: &SigningKey,
@@ -30,9 +31,12 @@ pub fn issue_access_token(
3031

3132
let claims = URL_SAFE_NO_PAD.encode(
3233
serde_json::to_string(&json!({
34+
"jti": Uuid::new_v4().to_string(),
3335
"sub": user_id.to_string(),
3436
"iss": issuer_url,
37+
"aud": audience,
3538
"iat": now,
39+
"nbf": now - 5,
3640
"exp": exp,
3741
}))
3842
.map_err(|e| AuthError::internal_with("JWT claims serialization", e))?,

0 commit comments

Comments
 (0)