use std::collections::BTreeSet;
use std::num::NonZeroUsize;
use std::sync::Arc;
use std::time::Duration;
use orbit_auth::{
Audience, Authority, Blake3State, Capability, Claims, FleetAuth, Keyring,
Purpose, Result, SecretKey, Validation,
};
use orbit_core::Fleet;
fn main() -> Result<()> {
let authority = Authority::new(
"shared-prod",
"identity-service",
Keyring::new(1, [(1, SecretKey::generate()?)])?,
)?;
let fleet = Arc::new(Fleet::join("auth-example", 1).unwrap());
let cache = FleetAuth::new(
fleet,
&authority,
SecretKey::generate()?,
NonZeroUsize::new(128).unwrap(),
Blake3State,
)?;
let now = 1_800_000_000;
let session_audience = Audience::new("session-service")?;
let session_state = cache.create_session("user:42", now, now + 3600)?;
let session = authority.issue_session(
Claims {
subject: "user:42".into(),
audience: session_audience.clone(),
purpose: Purpose::Session,
capabilities: BTreeSet::from([Capability::new("profile:read")?]),
issued_at: now,
not_before: now,
expires_at: now + 300,
},
&session_state,
)?;
let session_validator = authority.validator(Validation {
audience: session_audience,
purpose: Purpose::Session,
required_capabilities: BTreeSet::new(),
});
let signed_in = session_validator.validate_cached(
session.expose(),
now,
&cache,
Duration::from_secs(30),
&cache,
)?;
for (audience, purpose) in [
("public-api", Purpose::Access), ("realtime", Purpose::WebSocket), ("profile-worker", Purpose::Internal), ] {
let audience = Audience::new(audience)?;
let read = Capability::new("profile:read")?;
if !signed_in.has_capability(&read) {
return Err(orbit_auth::Error::MissingCapability);
}
let token = authority.issue_session(
Claims {
subject: signed_in.subject().into(),
audience: audience.clone(),
purpose,
capabilities: BTreeSet::from([read.clone()]),
issued_at: now,
not_before: now,
expires_at: now + 60,
},
&session_state,
)?;
let validator = authority.validator(Validation {
audience,
purpose,
required_capabilities: BTreeSet::from([read]),
});
let principal = validator.validate_cached(
token.expose(),
now,
&cache,
Duration::from_secs(30),
&cache,
)?;
assert_eq!(principal.subject(), signed_in.subject());
}
let refresh = authority.issue_session(
Claims {
subject: session_state.subject().into(),
audience: Audience::new("session-service")?,
purpose: Purpose::Refresh,
capabilities: BTreeSet::new(),
issued_at: now,
not_before: now,
expires_at: now + 300,
},
&session_state,
)?;
let refresh_validator = authority.validator(Validation {
audience: Audience::new("session-service")?,
purpose: Purpose::Refresh,
required_capabilities: BTreeSet::new(),
});
let renewed =
cache.refresh(&refresh_validator, refresh.expose(), now, now + 3600)?;
assert_eq!(renewed.id(), session_state.id());
cache.revoke_session(renewed.id(), now)?;
Ok(())
}