#![deny(unsafe_code)] #![deny(clippy::unwrap_used)] #![deny(warnings)] #![doc = include_str!("../README.md")] use crate::error::Error; use http::Uri; use openidconnect::{ core::{ CoreAuthDisplay, CoreAuthPrompt, CoreClaimName, CoreClaimType, CoreClientAuthMethod, CoreErrorResponseType, CoreGenderClaim, CoreGrantType, CoreJsonWebKey, CoreJsonWebKeyType, CoreJsonWebKeyUse, CoreJweContentEncryptionAlgorithm, CoreJweKeyManagementAlgorithm, CoreJwsSigningAlgorithm, CoreResponseMode, CoreResponseType, CoreRevocableToken, CoreRevocationErrorResponse, CoreSubjectIdentifierType, CoreTokenIntrospectionResponse, CoreTokenType, }, reqwest::async_http_client, AccessToken, ClientId, ClientSecret, CsrfToken, EmptyExtraTokenFields, IdTokenFields, IssuerUrl, Nonce, PkceCodeVerifier, RefreshToken, StandardErrorResponse, StandardTokenResponse, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; pub mod error; mod extractor; mod middleware; pub use extractor::{OidcAccessToken, OidcClaims, OidcRpInitiatedLogout}; pub use middleware::{OidcAuthLayer, OidcAuthMiddleware, OidcLoginLayer, OidcLoginMiddleware}; const SESSION_KEY: &str = "axum-oidc"; pub trait AdditionalClaims: openidconnect::AdditionalClaims + Clone + Sync + Send + Serialize + DeserializeOwned { } type OidcTokenResponse = StandardTokenResponse< IdTokenFields< AC, EmptyExtraTokenFields, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, >, CoreTokenType, >; pub type IdToken = openidconnect::IdToken< AZ, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, >; type Client = openidconnect::Client< AC, CoreAuthDisplay, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, CoreJsonWebKeyUse, CoreJsonWebKey, CoreAuthPrompt, StandardErrorResponse, OidcTokenResponse, CoreTokenType, CoreTokenIntrospectionResponse, CoreRevocableToken, CoreRevocationErrorResponse, >; type ProviderMetadata = openidconnect::ProviderMetadata< AdditionalProviderMetadata, CoreAuthDisplay, CoreClientAuthMethod, CoreClaimName, CoreClaimType, CoreGrantType, CoreJweContentEncryptionAlgorithm, CoreJweKeyManagementAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, CoreJsonWebKeyUse, CoreJsonWebKey, CoreResponseMode, CoreResponseType, CoreSubjectIdentifierType, >; pub type BoxError = Box; /// OpenID Connect Client #[derive(Clone)] pub struct OidcClient { scopes: Vec, client_id: String, client: Client, application_base_url: Uri, end_session_endpoint: Option, } impl OidcClient { /// create a new [`OidcClient`] by fetching the required information from the /// `/.well-known/openid-configuration` endpoint of the issuer. pub async fn discover_new( application_base_url: Uri, issuer: String, client_id: String, client_secret: Option, scopes: Vec, ) -> Result { let provider_metadata = ProviderMetadata::discover_async(IssuerUrl::new(issuer)?, async_http_client).await?; let end_session_endpoint = provider_metadata .additional_metadata() .end_session_endpoint .clone() .map(Uri::from_maybe_shared) .transpose() .map_err(Error::InvalidEndSessionEndpoint)?; let client = Client::from_provider_metadata( provider_metadata, ClientId::new(client_id.clone()), client_secret.map(ClientSecret::new), ); Ok(Self { scopes, client, client_id, application_base_url, end_session_endpoint, }) } } /// an empty struct to be used as the default type for the additional claims generic #[derive(Deserialize, Serialize, Debug, Clone, Copy, Default)] pub struct EmptyAdditionalClaims {} impl AdditionalClaims for EmptyAdditionalClaims {} impl openidconnect::AdditionalClaims for EmptyAdditionalClaims {} /// response data of the openid issuer after login #[derive(Debug, Deserialize)] struct OidcQuery { code: String, state: String, #[allow(dead_code)] session_state: String, } /// oidc session #[derive(Serialize, Deserialize, Debug)] #[serde(bound = "AC: Serialize + DeserializeOwned")] struct OidcSession { nonce: Nonce, csrf_token: CsrfToken, pkce_verifier: PkceCodeVerifier, authenticated: Option>, refresh_token: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(bound = "AC: Serialize + DeserializeOwned")] struct AuthenticatedSession { id_token: IdToken, access_token: AccessToken, } /// additional metadata that is discovered on client creation via the /// `.well-knwon/openid-configuration` endpoint. #[derive(Debug, Clone, Serialize, Deserialize)] struct AdditionalProviderMetadata { end_session_endpoint: Option, } impl openidconnect::AdditionalProviderMetadata for AdditionalProviderMetadata {} /// response extension flag to signal the [`OidcAuthLayer`] that the session should be cleared. #[derive(Clone, Copy)] pub struct ClearSessionFlag;