### Adding OAuth2 Provider (GitHub) Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Example code snippet demonstrating how to add a GitHub OAuth2 provider to the AuthEngine. ```rust use authkestra_providers_github::GitHubProvider; // Inside main, before wrapping engine in Arc: let github_provider = GitHubProvider::new( std::env::var("GITHUB_CLIENT_ID").unwrap(), std::env::var("GITHUB_CLIENT_SECRET").unwrap(), ); engine.add_provider(github_provider); ``` -------------------------------- ### Securing a Route Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Example of how to protect a route using Authkestra's `RequireAuth` extractor in an Axum application. ```rust use authkestra_axum::extract::RequireAuth; use axum::response::IntoResponse; async fn protected_profile(user: RequireAuth) -> impl IntoResponse { format!("Hello, user {}!", user.id()) } // In router: // .route("/profile", get(protected_profile)) ``` -------------------------------- ### Run the Application Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Command to compile and run the Rust application. ```bash cargo run ``` -------------------------------- ### Create a New Project Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Initialize a new Rust project and add necessary dependencies. ```bash cargo new authkestra-hello-world cd authkestra-hello-world ``` -------------------------------- ### Actix App Setup Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of setting up the Actix application with necessary data for authkestra integration. ```rust use actix_web::{web, App, HttpServer}; use authkestra_actix::SessionConfig; use authkestra_session::MemoryStore; use authkestra_token::TokenManager; use std::sync::Arc; #[actix_web::main] async fn main() -> std::io::Result<()> { let session_store: Arc = Arc::new(MemoryStore::new()); let token_manager = Arc::new(TokenManager::new("your-secret".to_string())); let session_config = SessionConfig::default(); HttpServer::new(move || { App::new() .app_data(web::Data::new(session_store.clone())) .app_data(web::Data::new(token_manager.clone())) .app_data(web::Data::new(session_config.clone())) // ... routes }) .bind("127.0.0.1:8080")? .run() .await } ``` -------------------------------- ### Initialize AuthEngine in main.rs Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Sets up the AuthEngine with a secret key, adds a local provider, and configures the Axum router. ```rust use axum::{routing::get, Router}; use authkestra_core::engine::{AuthEngine, EngineConfig}; use authkestra_core::providers::LocalProvider; use std::sync::Arc; #[tokio::main] async fn main() { // 1. Configure the engine let config = EngineConfig::default() .with_secret_key("super_secret_development_key_do_not_use_in_prod"); // 2. Instantiate the engine and add providers let mut engine = AuthEngine::new(config); // Add a local email/password provider for demonstration engine.add_provider(LocalProvider::new()); let engine = Arc::new(engine); // 3. Set up the Axum router let app = Router::new() .route("/", get(|| async { "Hello, Authkestra!" })) // Mount Authkestra routes under /auth .nest("/auth", authkestra_axum::routes(engine.clone())) // Use the engine as state if needed in other routes .with_state(engine); // 4. Run the server let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); println!("Server running on http://localhost:3000"); axum::serve(listener, app).await.unwrap(); } ``` -------------------------------- ### Add Dependencies to Cargo.toml Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch08-getting-started-tutorial.md Specifies the dependencies required for the project, including tokio, axum, and authkestra-core. ```toml [dependencies] tokio = { version = "1.0", features = ["full"] } axum = "0.7" authkestra-core = { version = "0.1", features = ["axum"] } # Include necessary providers if needed, e.g.: # authkestra-providers-github = "0.1" ``` -------------------------------- ### Getting Started with Authkestra Source: https://github.com/marcjazz/authkestra/blob/main/README.md Add the authkestra facade crate to your Cargo.toml with the desired features. ```toml [dependencies] # Use the facade with the features you need authkestra = { version = "0.1.1", features = ["axum", "github"] } ``` -------------------------------- ### Example Usage Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-oidc/README.md Example of initializing OidcProvider and generating an authorization URL. ```rust use authkestra_oidc::OidcProvider; use authkestra_core::OAuthProvider; #[tokio::main] async fn main() -> Result<(), Box> { // Initialize the provider using discovery let provider = OidcProvider::discover( "your_client_id".to_string(), "your_client_secret".to_string(), "http://localhost:8080/callback".to_string(), "https://accounts.google.com", // Issuer URL ).await?; // Generate an authorization URL let auth_url = provider.get_authorization_url( "random_state_string", &["email", "profile"], None // Optional PKCE code challenge ); println!("Redirect user to: {}", auth_url); // After the user is redirected back with a code: // let (identity, token) = provider.exchange_code_for_identity("code_from_callback", None).await?; Ok(()) } ``` -------------------------------- ### Run dependencies with Docker Compose Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Starts the necessary development dependencies using Docker Compose. ```bash docker-compose up -d ``` -------------------------------- ### Installation Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-session/README.md Add authkestra-session to your Cargo.toml. ```toml [dependencies] authkestra-session = { version = "0.1.1", features = ["sqlite"] } ``` -------------------------------- ### Quick Start with AuthkestraFromRef (Recommended) Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-axum/README.md The easiest way to integrate Authkestra with custom Axum state is using the AuthkestraFromRef macro: ```rust use axum::{routing::get, Router}; use authkestra_axum::{AuthSession, AuthkestraFromRef}; use authkestra::flow::Authkestra; use authkestra_flow::{Configured, Missing}; use authkestra_session::SessionStore; use tower_cookies::CookieManagerLayer; use std::sync::Arc; #[derive(Clone, AuthkestraFromRef)] struct AppState { #[authkestra] auth: Authkestra>, Missing>, // other fields... } async fn protected_handler(AuthSession(session): AuthSession) -> String { format!("Welcome back, {}!", session.identity.username.unwrap_or_default()) } fn app(state: AppState) -> Router { Router::new() .route("/protected", get(protected_handler)) .layer(CookieManagerLayer::new()) .with_state(state) } ``` -------------------------------- ### OAuth2 Flow - Initiate Login Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of initiating an OAuth2 login flow. ```rust use authkestra_actix::{initiate_oauth_login, handle_oauth_callback, logout, SessionConfig, OAuthCallbackParams}; use actix_web::{web, HttpRequest, HttpResponse, get}; use std::sync::Arc; // 1. Initiate Login #[get("/login")] async fn login(flow: web::Data, config: web::Data) -> HttpResponse { initiate_oauth_login(&flow, &config, &["user:email"]) } ``` -------------------------------- ### AuthEngine Builder Example Source: https://github.com/marcjazz/authkestra/blob/main/docs/rfc-001-architecture-migration.md Demonstrates the 'Golden Path' usage of the AuthEngine builder API to configure and construct an AuthEngine instance with various services. ```rust let engine = AuthEngine::builder() .with_provider(GoogleProvider::new(...)) .with_method(Credentials::new()) .with_session_store(MemoryStore::new()) .with_token_service(JwtService::new(...)) .build(); ``` -------------------------------- ### Run tests to ensure setup Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Executes all tests in the workspace to verify the development environment is set up correctly. ```bash cargo test --workspace ``` -------------------------------- ### OAuth2 Flow - Handle Callback (Server-Side Session) Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of handling the OAuth2 callback for server-side session management. ```rust use authkestra_actix::{initiate_oauth_login, handle_oauth_callback, logout, SessionConfig, OAuthCallbackParams}; use actix_web::{web, HttpRequest, HttpResponse, get}; use std::sync::Arc; // 2. Handle Callback (Server-Side Session) #[get("/callback")] async fn callback( req: HttpRequest, params: web::Query, flow: web::Data, store: web::Data>, config: web::Data, ) -> Result { handle_oauth_callback( req, &flow, params.into_inner(), store.get_ref().clone(), config.get_ref().clone(), "/dashboard" ).await } ``` -------------------------------- ### OAuth2 Flow - Logout Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of handling the logout process. ```rust use authkestra_actix::{initiate_oauth_login, handle_oauth_callback, logout, SessionConfig, OAuthCallbackParams}; use actix_web::{web, HttpRequest, HttpResponse, get}; use std::sync::Arc; // 3. Logout #[get("/logout")] async fn sign_out( req: HttpRequest, store: web::Data>, config: web::Data, ) -> Result { logout(req, store.get_ref().clone(), config.get_ref().clone(), "/").await } ``` -------------------------------- ### Example: Unified Authentication (Chained Strategies) Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-axum/README.md The Auth extractor allows you to use a central AuthkestraGuard that can try multiple authentication methods in order. ```rust use axum::{routing::get, Router, extract::FromRef}; use authkestra_axum::Auth; use authkestra_resource::{AuthEngineGuard, AuthPolicy}; use authkestra_resource::jwt::JwtStrategy; use authkestra_session::SessionStrategy; use std::sync::Arc; #[derive(Debug, Clone)] struct User { id: String } #[derive(Clone)] struct AppState { guard: Arc>, } impl FromRef for Arc> { fn from_ref(state: &AppState) -> Self { state.guard.clone() } } fn app() -> Router { let guard = AuthkestraGuard::builder() .strategy(JwtStrategy::new(jwt_config)) .strategy(SessionStrategy::new(session_store, "session_cookie")) .policy(AuthPolicy::FirstSuccess) .build(); let state = AppState { guard: Arc::new(guard), }; Router::new() .route("/protected", get(protected_handler)) .layer(CookieManagerLayer::new()) .with_state(state) } async fn protected_handler(Auth(user): Auth) -> String { format!("Welcome, user {}!", user.id) } ``` -------------------------------- ### Example of ABAC with AWS Cedar in Express.js Source: https://github.com/marcjazz/authkestra/blob/main/deep-search.md Illustrates how AWS Cedar can be used as middleware in an Express.js application to map client requests into authorization components. ```javascript import cedar from "@aws-sdk/cedar-policy"; import express from "express"; const app = express(); app.use(express.json()); // Assume cedar.CedarPolicy is initialized with your policies and schema const cedarPolicy = new cedar.CedarPolicy(); app.use(async (req, res, next) => { const request = { principal: { id: req.user.id, attributes: req.user.attributes }, action: { id: req.method }, resource: { id: req.path, attributes: req.resource.attributes }, context: { attributes: req.context.attributes }, }; try { const decision = await cedarPolicy.isAuthorized(request); if (decision.authorized) { next(); } else { res.status(403).send("Forbidden"); } } catch (error) { console.error("Authorization error:", error); res.status(500).send("Internal Server Error"); } }); // Your API routes would follow... app.listen(3000, () => { console.log("Server listening on port 3000"); }); ``` -------------------------------- ### AuthkestraFromRef derive macro usage Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-macros/README.md Example of using the AuthkestraFromRef derive macro on an Axum application state struct. ```rust use authkestra_axum::AuthkestraFromRef; use authkestra::flow::Authkestra; use authkestra_flow::{Configured, Missing}; use authkestra_session::SessionStore; use std::sync::Arc; #[derive(Clone, AuthkestraFromRef)] struct AppState { #[authkestra] auth: Authkestra>, Missing>, // Other application state... } ``` -------------------------------- ### Authentication Check Status Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-examples/static/index.html This JavaScript function checks the user's authentication status by fetching data from the /api/user endpoint. It dynamically updates the HTML to display user information or a login prompt. ```javascript async function checkStatus() { try { const res = await fetch('/api/user'); const app = document.getElementById('app'); if (res.ok) { const user = await res.json(); app.innerHTML = `

Welcome, ${user.id}!

You are successfully authenticated.

User Data:

${JSON.stringify(user, null, 2)}
Logout `; } else { app.innerHTML = `

Not Authenticated

Please log in to continue.

`; } } catch (err) { console.error(err); } } checkStatus(); ``` -------------------------------- ### AuthToken Extractor Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of using the AuthToken extractor to get and validate a JWT from the Authorization header. ```rust use authkestra_actix::AuthToken; use actix_web::{get, HttpResponse}; #[get("/api/data")] async fn protected_api(AuthToken(claims): AuthToken) -> HttpResponse { HttpResponse::Ok().json(claims) } ``` -------------------------------- ### Preview documentation locally Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Generates and opens the project's API documentation in the browser, excluding external dependencies. ```bash cargo doc --workspace --no-deps --open ``` -------------------------------- ### Using AuthEngineGuard Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-resource/README.md Demonstrates how to create and use AuthEngineGuard with a JWT strategy and authenticate a request. ```rust use authkestra_resource::{AuthEngineGuard, AuthPolicy}; use authkestra_resource::jwt::JwtStrategy; // Create a guard with a JWT strategy let guard = AuthEngineGuard::builder() .strategy(JwtStrategy::new(validation_config)) .policy(AuthPolicy::FirstSuccess) .build(); // Authenticate a request let result = guard.authenticate(&request_parts).await?; ``` -------------------------------- ### AuthSession Extractor Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of using the AuthSession extractor to access validated session data in a request handler. ```rust use authkestra_actix::AuthSession; use actix_web::{get, HttpResponse}; #[get("/profile")] async fn profile(AuthSession(session): AuthSession) -> HttpResponse { HttpResponse::Ok().json(session.identity) } ``` -------------------------------- ### Jwt Extractor (Offline Validation) Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-actix/README.md Example of using the Jwt extractor for offline JWT validation against a remote JWKS. ```rust use authkestra_actix::Jwt; use authkestra_resource::jwt::JwksCache; use actix_web::{get, HttpResponse, web}; use serde::Deserialize; use std::sync::Arc; #[derive(Deserialize)] struct MyClaims { sub: String, // ... } #[get("/api/external")] async fn external_api(Jwt(claims): Jwt) -> HttpResponse { HttpResponse::Ok().json(claims) } ``` -------------------------------- ### Create new Rust library crate Source: https://github.com/marcjazz/authkestra/blob/main/plans/ticket-10-plan.md Command to create a new Rust library crate named 'authkestra-engine'. ```bash cargo new --lib authkestra-engine ``` -------------------------------- ### authkestra-providers/src/lib.rs Source: https://github.com/marcjazz/authkestra/blob/main/plans/ticket-36-plan.md Exporting provider modules gated by features in the main library file. ```rust #[cfg(feature = "github")] pub mod github; #[cfg(feature = "google")] pub mod google; #[cfg(feature = "discord")] pub mod discord; ``` -------------------------------- ### Code Formatting Command Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch11-governance-and-contribution.md Command to format code according to project standards using rustfmt. ```bash cargo fmt ``` -------------------------------- ### Clone the repository Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Clones the Authkestra repository to your local machine. ```bash git clone https://github.com/your-username/authkestra.git cd authkestra ``` -------------------------------- ### Run Lints and Formatting Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Checks code formatting and lints the code using cargo fmt and cargo clippy. ```bash cargo fmt --all -- --check cargo clippy --workspace -- -D warnings ``` -------------------------------- ### Unit Test for Admin Policy Source: https://github.com/marcjazz/authkestra/blob/main/docs/book/ch10-testing-and-qa.md An example of a Rust unit test verifying that an AdminOnlyPolicy correctly grants access to a user with the 'admin' role. ```rust use authkestra_core::policy::{AdminOnlyPolicy, PolicyEvaluationResult}; use authkestra_core::user::UserContext; #[test] fn test_admin_policy_grants_access() { let policy = AdminOnlyPolicy::new(); let admin_user = UserContext::new().with_role("admin"); assert!(policy.evaluate(&admin_user).is_granted()); } ``` -------------------------------- ### SQL Session Store Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-session/README.md Requires one of postgres, mysql, or sqlite features. ```rust use authkestra_session::SqlSessionStore; use sqlx::SqlitePool; #[tokio::main] async fn main() -> Result<(), Box> { let pool = SqlitePool::connect("sqlite::memory:").await?; // Uses default table name "authkestra_sessions" let store = SqlSessionStore::new(pool); // Or with a custom table name // let store = SqlSessionStore::with_table_name(pool, "my_sessions".to_string()); Ok(()) } ``` -------------------------------- ### Manual Integration Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-axum/README.md If you prefer not to use the macro or need more control, you can manually implement the required traits: ```rust use axum::{routing::get, Router, extract::FromRef}; use authkestra_axum::{AuthSession, SessionConfig, AuthkestraAxumError}; use authkestra_session::SessionStore; use tower_cookies::CookieManagerLayer; use std::sync::Arc; #[derive(Clone)] struct AppState { session_store: Arc, session_config: SessionConfig, } impl FromRef for Arc { fn from_ref(state: &AppState) -> Self { state.session_store.clone() } } impl FromRef for SessionConfig { fn from_ref(state: &AppState) -> Self { state.session_config.clone() } } ``` -------------------------------- ### SessionStore and TokenService Interfaces Source: https://github.com/marcjazz/authkestra/blob/main/docs/rfc-001-architecture-migration.md Interfaces for stateful and stateless identity persistence. ```rust #[async_trait] pub trait SessionStore { async fn get(&self, id: &str) -> Option; async fn set(&self, session: Session) -> Result<(), AuthError>; } pub trait TokenService { fn issue(&self, identity: &Identity) -> Token; fn verify(&self, token: &str) -> Result; } ``` -------------------------------- ### Typestate Pattern Design for AuthEngine Source: https://github.com/marcjazz/authkestra/blob/main/plans/ticket-12-plan.md Defines the typestate markers and the basic structure of AuthEngine and AuthEngineBuilder using Rust. ```rust pub trait SessionStoreState {} pub struct NoSessionStore; impl SessionStoreState for NoSessionStore {} pub struct WithSessionStore(pub S); impl SessionStoreState for WithSessionStore {} pub struct AuthEngine { session_store: SessionState, // other fields like config, providers... } pub struct AuthEngineBuilder { session_store: SessionState, } ``` -------------------------------- ### Redis Store Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-session/README.md Requires the store-redis feature. ```rust use authkestra_session::RedisStore; // redis_url, prefix let store = RedisStore::new("redis://127.0.0.1/", "authkestra_session".to_string())?; ``` -------------------------------- ### Create a new feature branch Source: https://github.com/marcjazz/authkestra/blob/main/CONTRIBUTING.md Creates a new Git branch for implementing new features. ```bash git checkout -b my-feature-branch ``` -------------------------------- ### Working with Sessions Source: https://github.com/marcjazz/authkestra/blob/main/authkestra-session/README.md The SessionStore trait provides methods to manage sessions. ```rust use authkestra_session::{Session, SessionStore}; use authkestra_core::Identity; use chrono::{Utc, Duration}; use std::collections::HashMap; async fn manage_session(store: S) -> Result<(), Box> { let session = Session { id: "session_123".to_string(), identity: Identity { provider_id: "github".to_string(), external_id: "user_888".to_string(), email: Some("user@example.com".to_string()), username: Some("rust_dev".to_string()), attributes: HashMap::new(), }, expires_at: Utc::now() + Duration::hours(24), }; // Save a session store.save_session(&session).await?; // Load a session if let Some(loaded) = store.load_session("session_123").await? { println!("Loaded session for: {:?}", loaded.identity.username); } // Delete a session store.delete_session("session_123").await?; Ok(()) } ```