chore: full stack stability and migration fixes, plus react UI progress
This commit is contained in:
@@ -37,7 +37,7 @@ struct RefreshTokenGrant {
|
||||
|
||||
pub async fn logout(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Extension(auth_ctx): Extension<AuthContext>,
|
||||
) -> Result<StatusCode, (StatusCode, String)> {
|
||||
let claims = auth_ctx
|
||||
@@ -45,9 +45,8 @@ pub async fn logout(
|
||||
.ok_or((StatusCode::UNAUTHORIZED, "Not authenticated".to_string()))?;
|
||||
let user_id = Uuid::parse_str(&claims.sub)
|
||||
.map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid user ID".to_string()))?;
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
|
||||
sqlx::query("UPDATE refresh_tokens SET revoked = true WHERE user_id = $1 AND revoked = false")
|
||||
sqlx::query("UPDATE auth.refresh_tokens SET revoked = true WHERE user_id = $1 AND revoked = false")
|
||||
.bind(user_id)
|
||||
.execute(&db)
|
||||
.await
|
||||
@@ -82,15 +81,14 @@ pub async fn settings(
|
||||
}
|
||||
|
||||
pub async fn magiclink(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
State(_state): State<AuthState>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Json(payload): Json<RecoverRequest>,
|
||||
) -> Result<Json<Value>, (StatusCode, String)> {
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
let token = generate_confirmation_token();
|
||||
let hashed_token = hash_refresh_token(&token);
|
||||
|
||||
sqlx::query("UPDATE users SET confirmation_token = $1 WHERE email = $2")
|
||||
sqlx::query("UPDATE auth.users SET confirmation_token = $1 WHERE email = $2")
|
||||
.bind(&hashed_token)
|
||||
.bind(&payload.email)
|
||||
.execute(&db)
|
||||
@@ -103,8 +101,8 @@ pub async fn magiclink(
|
||||
}
|
||||
|
||||
pub async fn delete_user(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
State(_state): State<AuthState>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Extension(auth_ctx): Extension<AuthContext>,
|
||||
) -> Result<StatusCode, (StatusCode, String)> {
|
||||
let claims = auth_ctx
|
||||
@@ -112,15 +110,14 @@ pub async fn delete_user(
|
||||
.ok_or((StatusCode::UNAUTHORIZED, "Not authenticated".to_string()))?;
|
||||
let user_id = Uuid::parse_str(&claims.sub)
|
||||
.map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid user ID".to_string()))?;
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
|
||||
sqlx::query("UPDATE users SET deleted_at = now() WHERE id = $1")
|
||||
sqlx::query("UPDATE auth.users SET deleted_at = now() WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.execute(&db)
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
|
||||
sqlx::query("UPDATE refresh_tokens SET revoked = true WHERE user_id = $1")
|
||||
sqlx::query("UPDATE auth.refresh_tokens SET revoked = true WHERE user_id = $1")
|
||||
.bind(user_id)
|
||||
.execute(&db)
|
||||
.await
|
||||
@@ -131,16 +128,15 @@ pub async fn delete_user(
|
||||
|
||||
pub async fn signup(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
project_ctx: Option<Extension<ProjectContext>>,
|
||||
Json(payload): Json<SignUpRequest>,
|
||||
) -> Result<Json<AuthResponse>, (StatusCode, String)> {
|
||||
payload
|
||||
.validate()
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
|
||||
let user_exists = sqlx::query("SELECT id FROM users WHERE email = $1")
|
||||
let user_exists = sqlx::query("SELECT id FROM auth.users WHERE email = $1")
|
||||
.bind(&payload.email)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -158,7 +154,7 @@ pub async fn signup(
|
||||
|
||||
let user = sqlx::query_as::<_, User>(
|
||||
r#"
|
||||
INSERT INTO users (email, encrypted_password, raw_user_meta_data, confirmation_token, confirmed_at)
|
||||
INSERT INTO auth.users (email, encrypted_password, raw_user_meta_data, confirmation_token, confirmed_at)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING *
|
||||
"#,
|
||||
@@ -179,7 +175,7 @@ pub async fn signup(
|
||||
.unwrap_or(false);
|
||||
|
||||
if auto_confirm {
|
||||
sqlx::query("UPDATE users SET email_confirmed_at = now(), confirmation_token = NULL WHERE id = $1")
|
||||
sqlx::query("UPDATE auth.users SET email_confirmed_at = now(), confirmation_token = NULL WHERE id = $1")
|
||||
.bind(user.id)
|
||||
.execute(&db)
|
||||
.await
|
||||
@@ -215,12 +211,11 @@ pub async fn signup(
|
||||
|
||||
pub async fn login(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
project_ctx: Option<Extension<ProjectContext>>,
|
||||
Json(payload): Json<SignInRequest>,
|
||||
) -> Result<Json<AuthResponse>, (StatusCode, String)> {
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE email = $1")
|
||||
.bind(&payload.email)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -281,11 +276,10 @@ pub async fn login(
|
||||
}
|
||||
|
||||
pub async fn get_user(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
State(_state): State<AuthState>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Extension(auth_ctx): Extension<AuthContext>,
|
||||
) -> Result<Json<User>, (StatusCode, String)> {
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
let claims = auth_ctx
|
||||
.claims
|
||||
.ok_or((StatusCode::UNAUTHORIZED, "Not authenticated".to_string()))?;
|
||||
@@ -293,7 +287,7 @@ pub async fn get_user(
|
||||
let user_id = Uuid::parse_str(&claims.sub)
|
||||
.map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid user ID".to_string()))?;
|
||||
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -342,7 +336,7 @@ pub async fn token(
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
|
||||
req.validate()
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
|
||||
login(State(state), Some(Extension(db)), project_ctx, Json(req)).await
|
||||
login(State(state), Extension(db), project_ctx, Json(req)).await
|
||||
}
|
||||
"refresh_token" => {
|
||||
let req: RefreshTokenGrant = serde_json::from_value(payload)
|
||||
@@ -358,7 +352,7 @@ pub async fn token(
|
||||
let (revoked_token_hash, user_id, session_id) =
|
||||
sqlx::query_as::<_, (String, Uuid, Option<Uuid>)>(
|
||||
r#"
|
||||
UPDATE refresh_tokens
|
||||
UPDATE auth.refresh_tokens
|
||||
SET revoked = true, updated_at = now()
|
||||
WHERE token = $1 AND revoked = false
|
||||
RETURNING token, user_id, session_id
|
||||
@@ -386,7 +380,7 @@ pub async fn token(
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -419,20 +413,19 @@ pub async fn token(
|
||||
}
|
||||
|
||||
pub async fn recover(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
State(_state): State<AuthState>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Json(payload): Json<RecoverRequest>,
|
||||
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
|
||||
payload
|
||||
.validate()
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
|
||||
let token = generate_recovery_token();
|
||||
|
||||
let user = sqlx::query_as::<_, User>(
|
||||
r#"
|
||||
UPDATE users
|
||||
UPDATE auth.users
|
||||
SET recovery_token = $1
|
||||
WHERE email = $2
|
||||
RETURNING *
|
||||
@@ -455,18 +448,17 @@ pub async fn recover(
|
||||
|
||||
pub async fn verify(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
project_ctx: Option<Extension<ProjectContext>>,
|
||||
Json(payload): Json<VerifyRequest>,
|
||||
) -> Result<Json<AuthResponse>, (StatusCode, String)> {
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
|
||||
let user = match payload.r#type.as_str() {
|
||||
"signup" => {
|
||||
let hashed_input = hash_refresh_token(&payload.token);
|
||||
sqlx::query_as::<_, User>(
|
||||
r#"
|
||||
UPDATE users
|
||||
UPDATE auth.users
|
||||
SET email_confirmed_at = now(), confirmation_token = NULL
|
||||
WHERE confirmation_token = $1
|
||||
RETURNING *
|
||||
@@ -481,7 +473,7 @@ pub async fn verify(
|
||||
"recovery" => {
|
||||
let hashed_input = hash_refresh_token(&payload.token);
|
||||
let user = sqlx::query_as::<_, User>(
|
||||
"SELECT * FROM users WHERE recovery_token = $1"
|
||||
"SELECT * FROM auth.users WHERE recovery_token = $1"
|
||||
)
|
||||
.bind(&hashed_input)
|
||||
.fetch_optional(&db)
|
||||
@@ -492,14 +484,14 @@ pub async fn verify(
|
||||
if let Some(new_password) = &payload.password {
|
||||
let hashed = hash_password(new_password)
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
sqlx::query("UPDATE users SET encrypted_password = $1, recovery_token = NULL WHERE id = $2")
|
||||
sqlx::query("UPDATE auth.users SET encrypted_password = $1, recovery_token = NULL WHERE id = $2")
|
||||
.bind(&hashed)
|
||||
.bind(user.id)
|
||||
.execute(&db)
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
} else {
|
||||
sqlx::query("UPDATE users SET recovery_token = NULL WHERE id = $1")
|
||||
sqlx::query("UPDATE auth.users SET recovery_token = NULL WHERE id = $1")
|
||||
.bind(user.id)
|
||||
.execute(&db)
|
||||
.await
|
||||
@@ -510,7 +502,7 @@ pub async fn verify(
|
||||
"email_change" => {
|
||||
let hashed_input = hash_refresh_token(&payload.token);
|
||||
sqlx::query_as::<_, User>(
|
||||
"UPDATE users SET email = email_change, email_change = NULL, email_change_token_new = NULL WHERE email_change_token_new = $1 RETURNING *"
|
||||
"UPDATE auth.users SET email = email_change, email_change = NULL, email_change_token_new = NULL WHERE email_change_token_new = $1 RETURNING *"
|
||||
)
|
||||
.bind(&hashed_input)
|
||||
.fetch_optional(&db)
|
||||
@@ -522,7 +514,7 @@ pub async fn verify(
|
||||
let hashed_input = hash_refresh_token(&payload.token);
|
||||
sqlx::query_as::<_, User>(
|
||||
r#"
|
||||
UPDATE users
|
||||
UPDATE auth.users
|
||||
SET email_confirmed_at = now(), confirmation_token = NULL
|
||||
WHERE confirmation_token = $1
|
||||
RETURNING *
|
||||
@@ -558,11 +550,10 @@ pub async fn verify(
|
||||
|
||||
pub async fn update_user(
|
||||
State(state): State<AuthState>,
|
||||
db: Option<Extension<PgPool>>,
|
||||
Extension(db): Extension<PgPool>,
|
||||
Extension(auth_ctx): Extension<AuthContext>,
|
||||
Json(payload): Json<UserUpdateRequest>,
|
||||
) -> Result<Json<User>, (StatusCode, String)> {
|
||||
let db = db.map(|Extension(p)| p).unwrap_or_else(|| state.db.clone());
|
||||
payload
|
||||
.validate()
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
|
||||
@@ -579,7 +570,7 @@ pub async fn update_user(
|
||||
let token = generate_confirmation_token();
|
||||
let hashed_token = hash_refresh_token(&token);
|
||||
sqlx::query(
|
||||
"UPDATE users SET email_change = now(), email_change_token_new = $1 WHERE id = $2"
|
||||
"UPDATE auth.users SET email_change = now(), email_change_token_new = $1 WHERE id = $2"
|
||||
)
|
||||
.bind(&hashed_token)
|
||||
.bind(user_id)
|
||||
@@ -591,7 +582,7 @@ pub async fn update_user(
|
||||
|
||||
tx.commit().await.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -604,7 +595,7 @@ pub async fn update_user(
|
||||
if let Some(password) = &payload.password {
|
||||
let hashed = hash_password(password)
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
sqlx::query("UPDATE users SET encrypted_password = $1 WHERE id = $2")
|
||||
sqlx::query("UPDATE auth.users SET encrypted_password = $1 WHERE id = $2")
|
||||
.bind(hashed)
|
||||
.bind(user_id)
|
||||
.execute(&mut *tx)
|
||||
@@ -613,7 +604,7 @@ pub async fn update_user(
|
||||
}
|
||||
|
||||
if let Some(data) = &payload.data {
|
||||
sqlx::query("UPDATE users SET raw_user_meta_data = $1 WHERE id = $2")
|
||||
sqlx::query("UPDATE auth.users SET raw_user_meta_data = $1 WHERE id = $2")
|
||||
.bind(data)
|
||||
.bind(user_id)
|
||||
.execute(&mut *tx)
|
||||
@@ -623,7 +614,7 @@ pub async fn update_user(
|
||||
|
||||
tx.commit().await.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
|
||||
@@ -175,7 +175,7 @@ pub async fn verify(
|
||||
};
|
||||
|
||||
let jwt_secret = project_ctx.jwt_secret.as_str();
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM auth.users WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_optional(&state.db)
|
||||
.await
|
||||
|
||||
@@ -4,28 +4,17 @@ use axum::{
|
||||
middleware::Next,
|
||||
response::Response,
|
||||
};
|
||||
use common::{Config, ProjectContext};
|
||||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use common::{Config, ProjectContext, JwtConfig, JwtClaims};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthMiddlewareState {
|
||||
pub config: Config,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Claims {
|
||||
pub sub: String,
|
||||
pub email: Option<String>,
|
||||
pub role: String,
|
||||
pub exp: usize,
|
||||
pub iss: String,
|
||||
pub aud: Option<String>,
|
||||
pub jwt_config: JwtConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthContext {
|
||||
pub claims: Option<Claims>,
|
||||
pub claims: Option<JwtClaims>,
|
||||
pub role: String,
|
||||
}
|
||||
|
||||
@@ -44,19 +33,36 @@ pub async fn auth_middleware(
|
||||
if path.contains("/authorize") || path.contains("/callback") {
|
||||
return Ok(next.run(req).await);
|
||||
}
|
||||
|
||||
|
||||
// Allow public Signed URL access (GET only)
|
||||
if path.contains("/object/sign/") && req.method() == axum::http::Method::GET {
|
||||
return Ok(next.run(req).await);
|
||||
}
|
||||
|
||||
// Determine the secret to use
|
||||
let jwt_secret = if let Some(ctx) = &project_ctx {
|
||||
tracing::debug!("Using project-specific JWT secret");
|
||||
ctx.jwt_secret.clone()
|
||||
// Allow public WebSocket endpoint (JWT validation is handled in phx_join payload)
|
||||
if path.contains("/realtime/v1/websocket") {
|
||||
return Ok(next.run(req).await);
|
||||
}
|
||||
|
||||
// Determine the JWT config to use
|
||||
let jwt_config = if let Some(ctx) = &project_ctx {
|
||||
tracing::debug!(
|
||||
secret_source = "project",
|
||||
secret_preview = &ctx.jwt_secret[..ctx.jwt_secret.len().min(8)],
|
||||
"Using project-specific JWT secret"
|
||||
);
|
||||
JwtConfig {
|
||||
secret: ctx.jwt_secret.clone(),
|
||||
issuer: state.jwt_config.issuer.clone(),
|
||||
algorithm: state.jwt_config.algorithm,
|
||||
}
|
||||
} else {
|
||||
tracing::debug!("ProjectContext not found, using global JWT secret");
|
||||
state.config.jwt_secret.clone()
|
||||
tracing::debug!(
|
||||
secret_source = "global",
|
||||
secret_preview = &state.jwt_config.secret[..state.jwt_config.secret.len().min(8)],
|
||||
"ProjectContext not found, using global JWT secret"
|
||||
);
|
||||
state.jwt_config.clone()
|
||||
};
|
||||
|
||||
let auth_header = req
|
||||
@@ -84,18 +90,19 @@ pub async fn auth_middleware(
|
||||
};
|
||||
|
||||
if let Some(token) = token {
|
||||
let mut validation = Validation::new(Algorithm::HS256);
|
||||
validation.validate_exp = true;
|
||||
validation.validate_aud = false;
|
||||
// validation.set_audience(&["authenticated"]); // If we used audience
|
||||
tracing::debug!(
|
||||
token_preview = &token[..token.len().min(16)],
|
||||
token_length = token.len(),
|
||||
"Attempting JWT validation"
|
||||
);
|
||||
|
||||
match decode::<Claims>(
|
||||
&token,
|
||||
&DecodingKey::from_secret(jwt_secret.as_bytes()),
|
||||
&validation,
|
||||
) {
|
||||
Ok(token_data) => {
|
||||
let claims = token_data.claims;
|
||||
match jwt_config.validate_token(&token) {
|
||||
Ok(claims) => {
|
||||
tracing::debug!(
|
||||
role = &claims.role,
|
||||
sub = &claims.sub,
|
||||
"Token validated successfully"
|
||||
);
|
||||
let role = claims.role.clone();
|
||||
|
||||
let ctx = AuthContext {
|
||||
@@ -107,7 +114,11 @@ pub async fn auth_middleware(
|
||||
}
|
||||
Err(e) => {
|
||||
// Invalid token
|
||||
tracing::error!("Token validation failed: {}", e);
|
||||
tracing::error!(
|
||||
error = %e,
|
||||
secret_source = if project_ctx.is_some() { "project" } else { "global" },
|
||||
"Token validation failed"
|
||||
);
|
||||
return Err(StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ pub async fn callback(
|
||||
return Err((StatusCode::BAD_REQUEST, "Missing OAuth state parameter".to_string()));
|
||||
}
|
||||
|
||||
let existing_user = sqlx::query_as::<_, crate::models::User>("SELECT * FROM users WHERE email = $1")
|
||||
let existing_user = sqlx::query_as::<_, crate::models::User>("SELECT * FROM auth.users WHERE email = $1")
|
||||
.bind(&user_profile.email)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -253,7 +253,7 @@ pub async fn callback(
|
||||
|
||||
sqlx::query_as::<_, crate::models::User>(
|
||||
r#"
|
||||
INSERT INTO users (email, encrypted_password, raw_user_meta_data, email_confirmed_at)
|
||||
INSERT INTO auth.users (email, encrypted_password, raw_user_meta_data, email_confirmed_at)
|
||||
VALUES ($1, $2, $3, now())
|
||||
RETURNING *
|
||||
"#,
|
||||
|
||||
@@ -166,7 +166,7 @@ pub async fn sso_callback(
|
||||
let sub = claims.subject().as_str();
|
||||
|
||||
// 5. Create/Update User
|
||||
let existing_user = sqlx::query_as::<_, crate::models::User>("SELECT * FROM users WHERE email = $1")
|
||||
let existing_user = sqlx::query_as::<_, crate::models::User>("SELECT * FROM auth.users WHERE email = $1")
|
||||
.bind(email)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
@@ -185,7 +185,7 @@ pub async fn sso_callback(
|
||||
|
||||
sqlx::query_as::<_, crate::models::User>(
|
||||
r#"
|
||||
INSERT INTO users (email, encrypted_password, raw_user_meta_data)
|
||||
INSERT INTO auth.users (email, encrypted_password, raw_user_meta_data)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *
|
||||
"#,
|
||||
|
||||
@@ -162,7 +162,7 @@ pub async fn issue_refresh_token(
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO refresh_tokens (token, user_id, session_id, parent)
|
||||
INSERT INTO auth.refresh_tokens (token, user_id, session_id, parent)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
"#,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user