#[derive(Debug, Deserialize)] struct CreateAccessTokenRequest { name: Option, } async fn list_access_tokens( State(state): State, ) -> Result>, AppError> { Ok(Json(state.db.list_api_tokens()?)) } async fn create_access_token( State(state): State, Json(input): Json, ) -> Result<(StatusCode, Json), AppError> { let name = input .name .unwrap_or_else(|| "Home Assistant".into()) .trim() .to_string(); if name.is_empty() || name.len() > 80 { return Err(AppError::BadRequest( "token name must contain 1 to 80 characters".into(), )); } let secret = generate_access_token(); let item = ApiTokenInfo { id: Uuid::new_v4().to_string(), name, token_prefix: format!("{}...", secret.chars().take(24).collect::()), created_at: Utc::now(), }; state.db.save_api_token(&item, &hash_token(&secret))?; state.log( "info", "access_token.created", "Created a Home Assistant access token", json!({"token_id": item.id.clone(), "name": item.name.clone()}), ); Ok(( StatusCode::CREATED, Json(json!({"token": secret, "item": item})), )) } async fn delete_access_token( State(state): State, Path(id): Path, ) -> Result { if !state.db.delete_api_token(&id)? { return Err(AppError::NotFound(format!("access token {id}"))); } state.log( "info", "access_token.revoked", "Revoked a Home Assistant access token", json!({"token_id": id}), ); Ok(StatusCode::NO_CONTENT) }