Skip to main content

authkestra_engine/flow/
mod.rs

1//! # Engine Flow
2//!
3//! `authkestra-flow` orchestrates authentication flows, such as OAuth2 Authorization Code,
4//! PKCE, Client Credentials, and Device Flow. It acts as the bridge between the core traits
5//! and the framework-specific adapters.
6//!
7//! ## Key Components
8//!
9//! - **[`OAuth2Flow`]**: Orchestrates the standard OAuth2 Authorization Code flow.
10//! - **[`Engine`]**: The main service that holds providers, session stores, and token managers.
11//! - **[`EngineBuilder`]**: A builder for configuring and creating an [`Engine`] instance.
12//! - **[`CredentialsFlow`]**: Orchestrates direct credentials-based authentication (e.g., email/password).
13
14#![warn(missing_docs)]
15
16use crate::auth::{error::AuthError, state::Identity, CredentialsProvider, UserMapper};
17pub use crate::auth::{ErasedOAuthFlow, Session, SessionConfig, SessionStore};
18use async_trait::async_trait;
19use serde::{Deserialize, Serialize};
20
21pub use chrono;
22
23/// Context for an authentication flow.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[non_exhaustive]
26pub struct FlowContext {
27    /// The current state identifier.
28    pub state: String,
29    /// Parameters associated with the flow.
30    pub params: HashMap<String, String>,
31}
32
33/// Result of an authentication flow execution.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub enum FlowResult {
36    /// The flow is complete and has returned an identity.
37    Complete(Identity),
38    /// The flow requires a redirect to another URL.
39    Redirect(String),
40    /// The flow is pending (e.g., waiting for user interaction).
41    Pending,
42}
43
44/// Orchestrates the steps of an authentication protocol (e.g., OAuth2, Device Flow).
45#[async_trait]
46pub trait Flow: Send + Sync {
47    /// Returns the unique identifier for the flow.
48    fn id(&self) -> &str;
49
50    /// Executes the flow with the given context.
51    async fn execute(&self, ctx: FlowContext) -> Result<FlowResult, AuthError>;
52}
53
54use std::collections::HashMap;
55
56pub use crate::engine::{Configured, Engine, EngineBuilder, Missing};
57
58/// Client Credentials flow implementation.
59pub mod client_credentials_flow;
60/// Device Authorization flow implementation.
61pub mod device_flow;
62/// OAuth2 Authorization Code flow implementation.
63pub mod oauth2;
64
65pub use client_credentials_flow::ClientCredentialsFlow;
66pub use device_flow::{DeviceAuthorizationResponse, DeviceFlow};
67pub use oauth2::OAuth2Flow;
68
69/// Orchestrates a direct credentials flow.
70#[non_exhaustive]
71pub struct CredentialsFlow<P: CredentialsProvider, M: UserMapper = ()> {
72    provider: P,
73    mapper: Option<M>,
74}
75
76impl<P: CredentialsProvider> CredentialsFlow<P, ()> {
77    /// Create a new `CredentialsFlow` with the given provider.
78    pub fn new(provider: P) -> Self {
79        Self {
80            provider,
81            mapper: None,
82        }
83    }
84}
85
86impl<P: CredentialsProvider, M: UserMapper> CredentialsFlow<P, M> {
87    /// Create a new `CredentialsFlow` with the given provider and user mapper.
88    pub fn with_mapper(provider: P, mapper: M) -> Self {
89        Self {
90            provider,
91            mapper: Some(mapper),
92        }
93    }
94
95    /// Authenticate using the given credentials.
96    pub async fn authenticate(
97        &self,
98        creds: P::Credentials,
99    ) -> Result<(Identity, Option<M::LocalUser>), AuthError> {
100        let identity = self.provider.authenticate(creds).await?;
101
102        let local_user = if let Some(mapper) = &self.mapper {
103            Some(mapper.map_user(&identity).await?)
104        } else {
105            None
106        };
107
108        Ok((identity, local_user))
109    }
110}