Skip to main content

gestalt/
auth.rs

1use tonic::codegen::async_trait;
2
3use crate::error::Result;
4use crate::identity::{
5    AuthorizeRequest, AuthorizeResponse, GetGrantRequest, GetGrantResponse, IntrospectRequest,
6    IntrospectResponse, ListGrantsRequest, ListGrantsResponse, RevokeGrantRequest,
7    RevokeGrantResponse, TokenRequest, TokenResponse, UserInfoRequest, UserInfoResponse,
8};
9
10pub const CALLER_BEARER_TOKEN_METADATA_KEY: &str = "x-gestalt-caller-bearer-token";
11
12/// OAuth 2.0 authorization code grant type.
13pub const GRANT_TYPE_AUTHORIZATION_CODE: &str = "authorization_code";
14/// OAuth 2.0 token exchange grant type (RFC 8693).
15pub const GRANT_TYPE_TOKEN_EXCHANGE: &str = "urn:ietf:params:oauth:grant-type:token-exchange";
16/// OAuth 2.0 access token subject token type (RFC 8693).
17pub const SUBJECT_TOKEN_TYPE_ACCESS_TOKEN: &str = "urn:ietf:params:oauth:token-type:access_token";
18
19/// Caller-scoped identity metadata for grant-management RPCs.
20#[derive(Clone, Debug, Default, PartialEq, Eq)]
21pub struct IdentityCallContext {
22    /// The caller bearer token from gRPC metadata.
23    pub caller_bearer_token: String,
24}
25#[async_trait]
26/// Lifecycle and identity contract for Gestalt identity providers.
27pub trait IdentityProvider: Send + Sync + 'static {
28    /// Configures the provider before it starts serving requests.
29    async fn configure(
30        &self,
31        _name: &str,
32        _config: serde_json::Map<String, serde_json::Value>,
33    ) -> Result<()> {
34        Ok(())
35    }
36
37    /// Returns runtime metadata that should augment the static manifest.
38    fn metadata(&self) -> Option<crate::api::RuntimeMetadata> {
39        None
40    }
41
42    /// Returns non-fatal warnings the host should surface to users.
43    fn warnings(&self) -> Vec<String> {
44        Vec::new()
45    }
46
47    /// Performs an optional health check.
48    async fn health_check(&self) -> Result<()> {
49        Ok(())
50    }
51
52    /// Starts provider-owned background work after configuration.
53    async fn start(&self) -> Result<()> {
54        Ok(())
55    }
56
57    /// Shuts the provider down before the runtime exits.
58    async fn close(&self) -> Result<()> {
59        Ok(())
60    }
61
62    /// Starts an RFC 6749 authorization flow.
63    async fn authorize(&self, req: AuthorizeRequest) -> Result<AuthorizeResponse>;
64
65    /// Issues or exchanges tokens via the RFC 6749 token endpoint.
66    async fn token(&self, req: TokenRequest) -> Result<TokenResponse>;
67
68    /// Introspects a bearer token via RFC 7662.
69    async fn introspect(&self, req: IntrospectRequest) -> Result<IntrospectResponse>;
70
71    /// Returns profile claims for the authenticated caller.
72    async fn user_info(
73        &self,
74        call: IdentityCallContext,
75        req: UserInfoRequest,
76    ) -> Result<UserInfoResponse>;
77
78    /// Lists grant IDs visible to the caller.
79    async fn list_grants(
80        &self,
81        call: IdentityCallContext,
82        req: ListGrantsRequest,
83    ) -> Result<ListGrantsResponse>;
84
85    /// Returns one grant owned by the caller.
86    async fn get_grant(
87        &self,
88        call: IdentityCallContext,
89        req: GetGrantRequest,
90    ) -> Result<GetGrantResponse>;
91
92    /// Revokes one grant owned by the caller.
93    async fn revoke_grant(
94        &self,
95        call: IdentityCallContext,
96        req: RevokeGrantRequest,
97    ) -> Result<RevokeGrantResponse>;
98}
99pub(crate) fn caller_bearer_token_from_metadata(metadata: &tonic::metadata::MetadataMap) -> String {
100    metadata
101        .get(CALLER_BEARER_TOKEN_METADATA_KEY)
102        .and_then(|value| value.to_str().ok())
103        .map(str::trim)
104        .filter(|value| !value.is_empty())
105        .map(str::to_owned)
106        .unwrap_or_default()
107}