Skip to main content

authkestra_engine/flow/
mod.rs

1//! # Authkestra 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//! - **[`Authkestra`]**: The main service that holds providers, session stores, and token managers.
11//! - **[`AuthkestraBuilder`]**: A builder for configuring and creating an [`Authkestra`] 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)]
25pub struct FlowContext {
26    /// The current state identifier.
27    pub state: String,
28    /// Parameters associated with the flow.
29    pub params: HashMap<String, String>,
30}
31
32/// Result of an authentication flow execution.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub enum FlowResult {
35    /// The flow is complete and has returned an identity.
36    Complete(Identity),
37    /// The flow requires a redirect to another URL.
38    Redirect(String),
39    /// The flow is pending (e.g., waiting for user interaction).
40    Pending,
41}
42
43/// Orchestrates the steps of an authentication protocol (e.g., OAuth2, Device Flow).
44#[async_trait]
45pub trait Flow: Send + Sync {
46    /// Returns the unique identifier for the flow.
47    fn id(&self) -> &str;
48
49    /// Executes the flow with the given context.
50    async fn execute(&self, ctx: FlowContext) -> Result<FlowResult, AuthError>;
51}
52
53use std::collections::HashMap;
54
55pub use crate::engine::{Configured, Engine, EngineBuilder, Missing};
56
57/// Client Credentials flow implementation.
58pub mod client_credentials_flow;
59/// Device Authorization flow implementation.
60pub mod device_flow;
61/// OAuth2 Authorization Code flow implementation.
62pub mod oauth2;
63
64pub use client_credentials_flow::ClientCredentialsFlow;
65pub use device_flow::{DeviceAuthorizationResponse, DeviceFlow};
66pub use oauth2::OAuth2Flow;
67
68/// Orchestrates a direct credentials flow.
69pub struct CredentialsFlow<P: CredentialsProvider, M: UserMapper = ()> {
70    provider: P,
71    mapper: Option<M>,
72}
73
74impl<P: CredentialsProvider> CredentialsFlow<P, ()> {
75    /// Create a new `CredentialsFlow` with the given provider.
76    pub fn new(provider: P) -> Self {
77        Self {
78            provider,
79            mapper: None,
80        }
81    }
82}
83
84impl<P: CredentialsProvider, M: UserMapper> CredentialsFlow<P, M> {
85    /// Create a new `CredentialsFlow` with the given provider and user mapper.
86    pub fn with_mapper(provider: P, mapper: M) -> Self {
87        Self {
88            provider,
89            mapper: Some(mapper),
90        }
91    }
92
93    /// Authenticate using the given credentials.
94    pub async fn authenticate(
95        &self,
96        creds: P::Credentials,
97    ) -> Result<(Identity, Option<M::LocalUser>), AuthError> {
98        let identity = self.provider.authenticate(creds).await?;
99
100        let local_user = if let Some(mapper) = &self.mapper {
101            Some(mapper.map_user(&identity).await?)
102        } else {
103            None
104        };
105
106        Ok((identity, local_user))
107    }
108}