auth: add community token service seam

This commit is contained in:
a.tolmachev
2026-05-03 18:26:03 +00:00
parent 18b23fcc0d
commit ffcce360fc
10 changed files with 329 additions and 10 deletions
+100 -2
View File
@@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use crate::{
ids::{AuthProfileId, SecretId, WorkspaceId},
edition::{MachineAccessMode, OperationSecurityLevel},
ids::{AgentId, AuthProfileId, OperationId, SecretId, WorkspaceId},
protocol::AuthKind,
};
@@ -63,13 +64,55 @@ pub struct AuthProfile {
pub updated_at: OffsetDateTime,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AgentTokenGrantType {
AgentKey,
RefreshToken,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct IssueAgentTokenRequest {
pub grant_type: AgentTokenGrantType,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_token: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub scope: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct IssueOneTimeAgentTokenRequest {
pub agent_key: String,
pub operation_id: OperationId,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub scope: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct IssuedAgentTokenResponse {
pub access_token: String,
pub token_type: String,
pub expires_in: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_token: Option<String>,
pub machine_access_mode: MachineAccessMode,
pub security_level: OperationSecurityLevel,
pub agent_id: AgentId,
}
#[cfg(test)]
mod tests {
use serde_json::json;
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
use super::{ApiKeyHeaderAuthConfig, AuthConfig, AuthProfile};
use super::{
AgentTokenGrantType, ApiKeyHeaderAuthConfig, AuthConfig, AuthProfile,
IssueAgentTokenRequest, IssueOneTimeAgentTokenRequest, IssuedAgentTokenResponse,
};
use crate::{
edition::{MachineAccessMode, OperationSecurityLevel},
ids::{AuthProfileId, SecretId, WorkspaceId},
protocol::AuthKind,
};
@@ -94,4 +137,59 @@ mod tests {
assert_eq!(value["created_at"], json!("2026-03-25T12:00:00Z"));
assert_eq!(value["updated_at"], json!("2026-03-25T12:05:00Z"));
}
#[test]
fn issue_agent_token_request_serializes_stable_contract() {
let request = IssueAgentTokenRequest {
grant_type: AgentTokenGrantType::AgentKey,
agent_key: Some("crk_agent_secret".to_owned()),
refresh_token: None,
scope: vec!["tools:call".to_owned()],
};
let value = serde_json::to_value(&request).unwrap();
assert_eq!(value["grant_type"], json!("agent_key"));
assert_eq!(value["agent_key"], json!("crk_agent_secret"));
assert_eq!(value["scope"], json!(["tools:call"]));
assert_eq!(value.get("refresh_token"), None);
}
#[test]
fn issue_one_time_agent_token_request_serializes_stable_contract() {
let request = IssueOneTimeAgentTokenRequest {
agent_key: "crk_agent_secret".to_owned(),
operation_id: "op_01".into(),
scope: vec!["tools:call".to_owned()],
};
let value = serde_json::to_value(&request).unwrap();
assert_eq!(value["agent_key"], json!("crk_agent_secret"));
assert_eq!(value["operation_id"], json!("op_01"));
assert_eq!(value["scope"], json!(["tools:call"]));
}
#[test]
fn issued_agent_token_response_serializes_machine_access_metadata() {
let response = IssuedAgentTokenResponse {
access_token: "tok_01".to_owned(),
token_type: "Bearer".to_owned(),
expires_in: 300,
refresh_token: Some("rfr_01".to_owned()),
machine_access_mode: MachineAccessMode::ShortLivedToken,
security_level: OperationSecurityLevel::Elevated,
agent_id: "agt_01".into(),
};
let value = serde_json::to_value(&response).unwrap();
assert_eq!(value["access_token"], json!("tok_01"));
assert_eq!(value["token_type"], json!("Bearer"));
assert_eq!(value["expires_in"], json!(300));
assert_eq!(value["refresh_token"], json!("rfr_01"));
assert_eq!(value["machine_access_mode"], json!("short_lived_token"));
assert_eq!(value["security_level"], json!("elevated"));
assert_eq!(value["agent_id"], json!("agt_01"));
}
}
+3 -2
View File
@@ -18,8 +18,9 @@ pub use access::{
};
pub use agent::{Agent, AgentOperationBinding, AgentStatus, AgentVersion};
pub use auth::{
ApiKeyHeaderAuthConfig, ApiKeyQueryAuthConfig, AuthConfig, AuthProfile, BasicAuthConfig,
BearerAuthConfig,
AgentTokenGrantType, ApiKeyHeaderAuthConfig, ApiKeyQueryAuthConfig, AuthConfig, AuthProfile,
BasicAuthConfig, BearerAuthConfig, IssueAgentTokenRequest, IssueOneTimeAgentTokenRequest,
IssuedAgentTokenResponse,
};
pub use edition::{
EditionCapabilities, EditionLimits, MachineAccessMode, OperationSecurityLevel, ProductEdition,