[package]
name = "pas-external"
version = "4.0.2"
edition = "2024"
rust-version = "1.94"
license = "MIT OR Apache-2.0"
description = "Ppoppo Accounts System (PAS) external SDK -- OAuth2 PKCE, PASETO verification, Axum middleware, session liveness"
repository = "https://github.com/hakchin/ppoppo-sdk"
homepage = "https://accounts.ppoppo.com"
documentation = "https://docs.rs/pas-external"
keywords = ["oauth2", "pkce", "paseto", "axum", "authentication"]
categories = ["authentication", "web-programming"]

[features]
default = ["oauth", "token"]
# `oauth` now pulls in `tokio::sync` + `async-trait` to carry the #005
# break-glass sv-validator (`session_version` module). The validator
# depends on `AuthClient::get_user_info` (HTTP userinfo fallback) so it
# lives behind the `oauth` feature; non-oauth consumers never compile it.
oauth = [
    "dep:reqwest",
    "dep:sha2",
    "dep:rand",
    "dep:base64",
    "dep:url",
    "dep:tokio",
    "dep:async-trait",
]
token = ["dep:pasetors", "dep:hex", "dep:base64"]
# Well-known PASETO key set fetcher with TTL cache + rotation handling.
# Pulls in the HTTP client (oauth) and the token-verification primitives.
well-known-fetch = ["oauth", "token", "dep:tokio"]
# Server-side session liveness: AES-256-GCM refresh_token encryption at rest
# plus a PAS-backed liveness classifier. Consumers that persist PAS refresh
# tokens server-side should enable this feature.
session-liveness = ["oauth", "dep:aes-gcm", "dep:base64"]
# Axum middleware. Pulls in session-liveness so that the OAuth callback can
# encrypt PAS refresh_tokens before handing them to the consumer's
# SessionStore — the plaintext never reaches consumer code.
axum = ["oauth", "session-liveness", "dep:axum", "dep:axum-extra", "dep:tracing", "dep:urlencoding"]

[dependencies]
# Core types
derive_more = { version = "2", default-features = false, features = ["display", "from_str", "from", "into"] }
ulid = { version = "1", features = ["serde"] }

# Token verification
pasetors = { version = "0.7", default-features = false, features = ["v4", "std"], optional = true }
hex = { version = "0.4", optional = true }

# OAuth2 HTTP client
reqwest = { version = "0.13", default-features = false, features = ["json", "form", "rustls"], optional = true }
url = { version = "2", optional = true }

# PKCE
sha2 = { version = "0.11", optional = true }
base64 = { version = "0.22", optional = true }
rand = { version = "0.10", optional = true }

# Session liveness: AES-256-GCM at-rest encryption for refresh_token
aes-gcm = { version = "0.10", features = ["aes"], optional = true }

# Well-known keyset and #005 sv-validator use `tokio::sync::RwLock`.
tokio = { version = "1", default-features = false, features = ["sync"], optional = true }

# Async trait methods for SessionVersionCache in the `session_version`
# module (#005 break-glass cache primitives).
async-trait = { version = "0.1", optional = true }

# Serialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Error handling
thiserror = "2"

# Axum middleware (feature = "axum")
axum = { version = "0.8", optional = true }
axum-extra = { version = "0.12", features = ["cookie-private"], optional = true }
tracing = { version = "0.1", optional = true }
time = { version = "0.3", features = ["serde", "serde-well-known", "parsing"] }
urlencoding = { version = "2", optional = true }

[dev-dependencies]
static_assertions = "1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

[lints.rust]
unsafe_code = "forbid"

[lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
panic = "deny"
