Skip to content

Auth

The server uses Oso Cloud for authorization. Every mutation and sensitive query is protected by auth guards that check permissions against the Oso Cloud policy engine.

Wrapper around the Oso Cloud SDK:

pub struct OsoClient {
client: oso_cloud::Oso,
}
impl OsoClient {
pub fn new(url: &str, api_key: &str) -> Self;
pub async fn authorize(&self, actor: &str, action: &str, resource: &str) -> Result<bool>;
pub async fn tell(&self, fact: &str, args: &[&str]) -> Result<()>;
pub async fn delete(&self, fact: &str, args: &[&str]) -> Result<()>;
pub async fn bulk_tell(&self, facts: Vec<(String, Vec<String>)>) -> Result<()>;
pub async fn bulk_delete(&self, facts: Vec<(String, Vec<String>)>) -> Result<()>;
pub async fn bulk(&self, tells: Vec<...>, deletes: Vec<...>) -> Result<()>;
pub async fn query(&self, fact: &str, args: &[&str]) -> Result<Vec<...>>;
}

Two async-graphql guards protect resolvers:

Checks that an AuthUser exists in the GraphQL context (set from X-Uid header):

pub struct SignedIn;
impl Guard for SignedIn {
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
ctx.data::<AuthUser>()
.map(|_| ())
.map_err(|_| "Unauthorized".into())
}
}

Checks Oso Cloud authorization for a specific action on a resource:

pub struct HasPermission {
action: String,
id_arg: String, // which GraphQL argument contains the resource ID
}
impl HasPermission {
pub fn new(action: &str) -> Self;
pub fn with_id_arg(action: &str, id_arg: &str) -> Self;
}

Usage in resolvers:

#[graphql(guard = "SignedIn.and(HasPermission::new(\"read\"))")]
async fn resource(&self, ctx: &Context<'_>, id: ID) -> Result<Resource> {
// ...
}
#[graphql(guard = "SignedIn.and(HasPermission::with_id_arg(\"delete\", \"resource_id\"))")]
async fn delete_resource(&self, ctx: &Context<'_>, resource_id: ID) -> Result<bool> {
// ...
}

Authorization repos manage Oso Cloud facts alongside database writes. Facts are written before database operations (Oso-first ordering).

Manages resource ownership and sharing facts:

  • tell("has_role", [user, "owner", resource]) on create
  • delete("has_role", [user, "owner", resource]) on delete
  • tell("has_role", [user, permission, resource]) on share

Manages folder ownership facts:

  • tell("has_role", [user, "owner", folder]) on create
  • delete("has_role", [user, "owner", folder]) on delete

Extracted from HTTP headers in the GraphQL handler:

pub struct AuthUser {
pub id: String,
}

The handler checks X-Impersonate-Uid first (for admin impersonation), falling back to X-Uid.

  • GraphQL — resolvers that use these guards
  • Resources — resource repository called after auth
  • Folders — folder repository called after auth
  • Overview — server architecture