diff --git a/src/authenticator.rs b/src/authenticator.rs index a54cede..bdade8f 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -1,3 +1,4 @@ +//! Module contianing the core functionality for OAuth2 Authentication. use crate::authenticator_delegate::{ AuthenticatorDelegate, DefaultAuthenticatorDelegate, FlowDelegate, }; @@ -15,6 +16,8 @@ use std::path::PathBuf; use std::sync::Mutex; use std::time::Duration; +/// Authenticator is responsible for fetching tokens, handling refreshing tokens, +/// and optionally persisting tokens to disk. pub struct Authenticator { hyper_client: hyper::Client, app_secret: ApplicationSecret, @@ -27,6 +30,7 @@ impl Authenticator where C: hyper::client::connect::Connect + 'static, { + /// Return the current token for the provided scopes. pub async fn token<'a, T>(&'a self, scopes: &'a [T]) -> Result where T: AsRef, @@ -77,6 +81,7 @@ where } } +/// Configure an Authenticator using the builder pattern. pub struct AuthenticatorBuilder { hyper_client_builder: C, app_secret: ApplicationSecret, @@ -85,8 +90,24 @@ pub struct AuthenticatorBuilder { auth_flow: F, } +/// Create an authenticator that uses the installed flow. +/// ``` +/// # async fn foo() { +/// # use yup_oauth2::InstalledFlowReturnMethod; +/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate; +/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder( +/// app_secret, +/// InstalledFlowReturnMethod::HTTPRedirect, +/// ) +/// .build() +/// .await +/// .expect("failed to create authenticator"); +/// # } +/// ``` pub struct InstalledFlowAuthenticator; impl InstalledFlowAuthenticator { + /// Use the builder pattern to create an Authenticator that uses the installed flow. pub fn builder( app_secret: ApplicationSecret, method: InstalledFlowReturnMethod, @@ -98,8 +119,19 @@ impl InstalledFlowAuthenticator { } } +/// Create an authenticator that uses the device flow. +/// ``` +/// # async fn foo() { +/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret) +/// .build() +/// .await +/// .expect("failed to create authenticator"); +/// # } +/// ``` pub struct DeviceFlowAuthenticator; impl DeviceFlowAuthenticator { + /// Use the builder pattern to create an Authenticator that uses the device flow. pub fn builder( app_secret: ApplicationSecret, ) -> AuthenticatorBuilder { @@ -107,7 +139,45 @@ impl DeviceFlowAuthenticator { } } +/// Methods available when building any Authenticator. +/// ``` +/// # async fn foo() { +/// # let custom_hyper_client = hyper::Client::new(); +/// # let custom_auth_delegate = yup_oauth2::authenticator_delegate::DefaultAuthenticatorDelegate; +/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret) +/// .hyper_client(custom_hyper_client) +/// .persist_tokens_to_disk("/tmp/tokenfile.json") +/// .auth_delegate(Box::new(custom_auth_delegate)) +/// .build() +/// .await +/// .expect("failed to create authenticator"); +/// # } +/// ``` impl AuthenticatorBuilder { + /// Create the authenticator. + pub async fn build(self) -> io::Result> + where + C: HyperClientBuilder, + F: Into, + { + let hyper_client = self.hyper_client_builder.build_hyper_client(); + let storage = match self.storage_type { + StorageType::Memory => Storage::Memory { + tokens: Mutex::new(storage::JSONTokens::new()), + }, + StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?), + }; + + Ok(Authenticator { + hyper_client, + app_secret: self.app_secret, + storage, + auth_delegate: self.auth_delegate, + auth_flow: self.auth_flow.into(), + }) + } + fn with_auth_flow( app_secret: ApplicationSecret, auth_flow: F, @@ -153,31 +223,23 @@ impl AuthenticatorBuilder { ..self } } - - /// Create the authenticator. - pub async fn build(self) -> io::Result> - where - C: HyperClientBuilder, - F: Into, - { - let hyper_client = self.hyper_client_builder.build_hyper_client(); - let storage = match self.storage_type { - StorageType::Memory => Storage::Memory { - tokens: Mutex::new(storage::JSONTokens::new()), - }, - StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?), - }; - - Ok(Authenticator { - hyper_client, - app_secret: self.app_secret, - storage, - auth_delegate: self.auth_delegate, - auth_flow: self.auth_flow.into(), - }) - } } +/// Methods available when building a device flow Authenticator. +/// ``` +/// # async fn foo() { +/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate; +/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret) +/// .device_code_url("foo") +/// .flow_delegate(Box::new(custom_flow_delegate)) +/// .wait_duration(std::time::Duration::from_secs(120)) +/// .grant_type("foo") +/// .build() +/// .await +/// .expect("failed to create authenticator"); +/// # } +/// ``` impl AuthenticatorBuilder { /// Use the provided device code url. pub fn device_code_url(self, url: impl Into>) -> Self { @@ -224,6 +286,22 @@ impl AuthenticatorBuilder { } } +/// Methods available when building an installed flow Authenticator. +/// ``` +/// # async fn foo() { +/// # use yup_oauth2::InstalledFlowReturnMethod; +/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate; +/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder( +/// app_secret, +/// InstalledFlowReturnMethod::HTTPRedirect, +/// ) +/// .flow_delegate(Box::new(custom_flow_delegate)) +/// .build() +/// .await +/// .expect("failed to create authenticator"); +/// # } +/// ``` impl AuthenticatorBuilder { /// Use the provided FlowDelegate. pub fn flow_delegate(self, flow_delegate: Box) -> Self { @@ -285,8 +363,10 @@ mod private { /// A trait implemented for any hyper::Client as well as teh DefaultHyperClient. pub trait HyperClientBuilder { + /// The hyper connector that the resulting hyper client will use. type Connector: hyper::client::connect::Connect + 'static; + /// Create a hyper::Client fn build_hyper_client(self) -> hyper::Client; } diff --git a/src/authenticator_delegate.rs b/src/authenticator_delegate.rs index e5ad5e3..c55c2c7 100644 --- a/src/authenticator_delegate.rs +++ b/src/authenticator_delegate.rs @@ -1,3 +1,5 @@ +//! Module containing types related to delegates. + use crate::error::{Error, PollError, RefreshError}; use std::error::Error as StdError; diff --git a/src/error.rs b/src/error.rs index a8b66e1..619b984 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +//! Module containing various error types. + use std::error::Error as StdError; use std::fmt; use std::io; diff --git a/src/lib.rs b/src/lib.rs index 79670c2..824eb9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,19 +20,19 @@ //! based on the Google APIs; it may or may not work with other providers. //! //! # Installed Flow Usage -//! The `InstalledFlow` involves showing a URL to the user (or opening it in a browser) +//! The installed flow involves showing a URL to the user (or opening it in a browser) //! and then either prompting the user to enter a displayed code, or make the authorizing //! website redirect to a web server spun up by this library and running on localhost. //! -//! In order to use the interactive method, use the `InstalledInteractive` `FlowType`; -//! for the redirect method, use `InstalledRedirect`, with the port number to let the -//! server listen on. +//! In order to use the interactive method, use the `Interactive` `InstalledFlowReturnMethod`; +//! for the redirect method, use `HTTPRedirect`. //! //! You can implement your own `AuthenticatorDelegate` in order to customize the flow; -//! the `InstalledFlow` uses the `present_user_url` method. +//! the installed flow uses the `present_user_url` method. //! -//! The returned `Token` is stored permanently in the given token storage in order to -//! authorize future API requests to the same scopes. +//! The returned `Token` will be stored in memory in order to authorize future +//! API requests to the same scopes. The tokens can optionally be persisted to +//! disk by using `persist_tokens_to_disk` when creating the authenticator. //! //! The following example, which is derived from the (actual and runnable) example in //! `examples/test-installed/`, shows the basics of using this crate: @@ -68,6 +68,7 @@ //! } //! ``` //! +#![deny(missing_docs)] pub mod authenticator; pub mod authenticator_delegate; mod device; diff --git a/src/service_account.rs b/src/service_account.rs index 2327d1f..b88d5c8 100644 --- a/src/service_account.rs +++ b/src/service_account.rs @@ -69,15 +69,25 @@ fn decode_rsa_key(pem_pkcs8: &str) -> Result { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ServiceAccountKey { #[serde(rename = "type")] + /// key_type pub key_type: Option, + /// project_id pub project_id: Option, + /// private_key_id pub private_key_id: Option, + /// private_key pub private_key: String, + /// client_email pub client_email: String, + /// client_id pub client_id: Option, + /// auth_uri pub auth_uri: Option, + /// token_uri pub token_uri: String, + /// auth_provider_x509_cert_url pub auth_provider_x509_cert_url: Option, + /// client_x509_cert_url pub client_x509_cert_url: Option, } @@ -150,8 +160,19 @@ impl JWTSigner { } } +/// Create an authenticator that uses a service account. +/// ``` +/// # async fn foo() { +/// # let service_key = yup_oauth2::service_account_key_from_file("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_key) +/// .build() +/// .expect("failed to create authenticator"); +/// # } +/// ``` pub struct ServiceAccountAuthenticator; impl ServiceAccountAuthenticator { + /// Use the builder pattern to create an authenticator that uses a service + /// account. pub fn builder(key: ServiceAccountKey) -> Builder { Builder { client: DefaultHyperClient, @@ -161,12 +182,25 @@ impl ServiceAccountAuthenticator { } } +/// Configure a service account authenticator using the builder pattern. pub struct Builder { client: C, key: ServiceAccountKey, subject: Option, } +/// Methods available when building a service account authenticator. +/// ``` +/// # async fn foo() { +/// # let custom_hyper_client = hyper::Client::new(); +/// # let service_key = yup_oauth2::service_account_key_from_file("/tmp/foo").unwrap(); +/// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_key) +/// .hyper_client(custom_hyper_client) +/// .subject("foo") +/// .build() +/// .expect("failed to create authenticator"); +/// # } +/// ``` impl Builder { /// Use the provided hyper client. pub fn hyper_client(self, hyper_client: NewC) -> Builder { @@ -178,9 +212,9 @@ impl Builder { } /// Use the provided subject. - pub fn subject(self, subject: String) -> Self { + pub fn subject(self, subject: impl Into) -> Self { Builder { - subject: Some(subject), + subject: Some(subject.into()), ..self } } @@ -194,6 +228,7 @@ impl Builder { } } +/// ServiceAccountAccess can fetch oauth tokens using a service account. pub struct ServiceAccountAccess { client: hyper::Client, key: ServiceAccountKey, @@ -223,6 +258,7 @@ where }) } + /// Return the current token for the provided scopes. pub async fn token(&self, scopes: &[T]) -> Result where T: AsRef, diff --git a/src/types.rs b/src/types.rs index c8d5510..34218b3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -80,8 +80,8 @@ pub struct ApplicationSecret { pub token_uri: String, /// The authorization server endpoint URI. pub auth_uri: String, + /// The redirect uris. pub redirect_uris: Vec, - /// Name of the google project the credentials are associated with pub project_id: Option, /// The service account email associated with the client. @@ -93,27 +93,13 @@ pub struct ApplicationSecret { pub client_x509_cert_url: Option, } -impl ApplicationSecret { - pub const fn empty() -> Self { - ApplicationSecret { - client_id: String::new(), - client_secret: String::new(), - token_uri: String::new(), - auth_uri: String::new(), - redirect_uris: Vec::new(), - project_id: None, - client_email: None, - auth_provider_x509_cert_url: None, - client_x509_cert_url: None, - } - } -} - /// A type to facilitate reading and writing the json secret file /// as returned by the [google developer console](https://code.google.com/apis/console) #[derive(Deserialize, Serialize, Default)] pub struct ConsoleApplicationSecret { + /// web app secret pub web: Option, + /// installed app secret pub installed: Option, }