From 3efcb85d6ecbcb842db94be384b7a250055cdb41 Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Wed, 23 Sep 2026 21:45:20 +0100 Subject: [PATCH] Add documentation --- README.md | 11 +- src/credentials/access_token.rs | 31 ++++ src/credentials/client_credentials.rs | 124 ++++++++++----- src/credentials/mod.rs | 221 ++++++++++++++++++++++---- src/credentials/web_server.rs | 112 +++++++++++++ src/lib.rs | 11 +- 6 files changed, 429 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index ae7a401..957abad 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Salesforce authentication SDK for Rust, supporting the OAuth2.0 flows: - [Client Credentials](#client-credentials) - JWT, - [sfdxAuthUrl](#sfdx-authentication-url), -- Web Server, +- [Web Server](#oauth-web-server-flow), (this flow waits for user interaction in a browser) ## Examples @@ -65,8 +65,6 @@ async fn main(){ } ``` - - ### SFDX Authentication URL Export the SFDX authentication URL using the [SFDX CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm), via the following command ```bash @@ -125,3 +123,10 @@ Alternatively you could enter the sfdxAuthUrl directly as a string via: let config = SalesforceCredentials::sfdx_url("force://PlatformCLI::4sdf2348kS0Qqf3GEL....@example.my.salesforce.com").unwrap(); let session = config.connect().await.unwrap(); ``` + + +### OAuth Web Server Flow +With This authorization flow, users can authenticate themselves using a browser. +The callback url is then invoked by Salesforce that sends a code with which the access_token and refresh token can be requested. + +<<<<<<<<<<<<<<<<<<<<<<<<< Continue HERE \ No newline at end of file diff --git a/src/credentials/access_token.rs b/src/credentials/access_token.rs index 0c3c5d9..dee438e 100644 --- a/src/credentials/access_token.rs +++ b/src/credentials/access_token.rs @@ -1,3 +1,9 @@ +//! Access token authentication module. +//! +//! This module provides functionality for authenticating with Salesforce using an existing +//! access token. It supports both simple access token authentication and refresh token +//! capabilities when additional credentials are provided. + use crate::credentials::{required, SalesforceAuthFlow, SalesforceCredentials}; use crate::error::SalesforceAuthError; use crate::salesforce_token_response::SalesforceTokenResponse; @@ -9,6 +15,15 @@ impl SalesforceCredentials { /// supplied, the resulting [`SalesforceAuthSession`] can later refresh its /// access token with [`SalesforceAuthSession::refresh_access_token`]. /// + /// # Parameters + /// + /// * `access_token` - The existing Salesforce access token + /// * `instance_url` - The Salesforce instance URL (e.g., "https://example.my.salesforce.com") + /// * `refresh_token` - Optional refresh token for renewing the access token + /// * `client_id` - Optional client ID from the connected app + /// * `client_secret` - Optional client secret from the connected app + /// * `login_url` - Optional Salesforce login URL (e.g., "https://login.salesforce.com") + /// /// # Examples /// /// ```rust @@ -26,6 +41,11 @@ impl SalesforceCredentials { /// assert_eq!(config.flow, SalesforceAuthFlow::AccessToken); /// assert_eq!(config.access_token.as_deref(), Some("access-token")); /// ``` + /// + /// # Note + /// An access token has a limited lifetime and will expire, since there is no refresh_token, + /// the application will panic when its expired. + /// Only use this authentication flow for short-lived applications pub fn access_token( access_token: impl Into, instance_url: impl Into, @@ -52,6 +72,17 @@ impl SalesforceCredentials { /// This function does not validate the access token with Salesforce. It simply /// wraps the token and related metadata in a [`SalesforceAuthSession`]. /// + /// # Parameters + /// + /// This method uses the following fields from `self`: + /// * `access_token` - The existing Salesforce access token (required) + /// * `login_url` - The Salesforce login URL (required) + /// + /// # Returns + /// + /// Returns a `Result` containing a `SalesforceTokenResponse` on success, or a + /// `SalesforceAuthError` if required fields are missing. + /// /// # Examples /// /// ```rust diff --git a/src/credentials/client_credentials.rs b/src/credentials/client_credentials.rs index 6bfe676..b67f4dc 100644 --- a/src/credentials/client_credentials.rs +++ b/src/credentials/client_credentials.rs @@ -1,24 +1,72 @@ +//! OAuth 2.0 Client Credentials flow implementation for Salesforce authentication. +//! +//! This module provides functionality to authenticate with Salesforce using the +//! OAuth 2.0 Client Credentials grant type, which is suitable for server-to-server +//! integrations where no user interaction is required. + use log::trace; use crate::credentials::{http_client, required, SalesforceAuthFlow, SalesforceCredentials}; use crate::salesforce_token_response::SalesforceTokenResponse; use crate::SalesforceAuthError; impl SalesforceCredentials { - /// Creates a configuration for the OAuth 2.0 client mod flow. + /// Connects to Salesforce using the OAuth 2.0 Client Credentials flow. /// - /// # Examples + /// # Parameters + /// + /// - `login_url`: The Salesforce login url, e.g. `https://login.salesforce.com` + /// - `client_id`: The Connected App Client Id + /// - `client_secret`: The Connected App Client Secret + /// + /// # Example /// /// ```rust - /// use rustsf_auth::{SalesforceCredentials, SalesforceAuthFlow}; + /// use oauth2::http::header::AUTHORIZATION; + /// use oauth2::http::{HeaderMap, HeaderValue}; + /// use crate::credentials::SalesforceCredentials; /// - /// let config = SalesforceCredentials::client_credentials( - /// "https://login.salesforce.com", - /// "client-id", - /// "client-secret", - /// ); + /// pub const CONNECT_TIMEOUT: u64 = 15; + /// pub const REQUEST_TIMEOUT: u64 = 30; + /// #[tokio::main] + /// async fn main(){ + /// // The client id and secret, (should never be hardcoded) + /// let login_url = "https://example.my.salesforce.com/"; + /// let client_id = "client_id"; + /// let client_secret = "client_secret"; /// - /// assert_eq!(config.flow, SalesforceAuthFlow::ClientCredentials); - /// assert_eq!(config.client_id.as_deref(), Some("client-id")); + /// // The Credentials configuration + /// let config = SalesforceCredentials::client_credentials( + /// login_url, + /// client_id, + /// client_secret); + /// + /// // Constructing the authentication session and connecting to Salesforce + /// let session = config.connect().await.unwrap(); + /// + /// // Build the headers to include the access token + /// let mut headers = HeaderMap::new(); + /// let auth_value = format!("Bearer {}", session.access_token().await.unwrap()); + /// headers.insert(AUTHORIZATION, HeaderValue::from_str(&auth_value).unwrap()); + /// + /// // A REST API request + /// let response = reqwest::Client::builder() + /// .redirect(reqwest::redirect::Policy::none()) + /// .connect_timeout(std::time::Duration::from_secs(CONNECT_TIMEOUT)) + /// .timeout(std::time::Duration::from_secs(REQUEST_TIMEOUT)) + /// .build() + /// .unwrap() + /// .get(format!("{}/services/data", session.instance_url)) + /// .headers(headers) + /// .send() + /// .await + /// .unwrap(); + /// + /// if response.status().is_success() { + /// println!("SUCCESS Response: {:?}", response.text().await.unwrap()); + /// } else { + /// println!("ERROR Response: {:?}", response.text().await.unwrap()); + /// } + /// } /// ``` pub fn client_credentials( login_url: impl Into, @@ -38,55 +86,45 @@ impl SalesforceCredentials { } } - /// Authenticates to Salesforce using the OAuth 2.0 client mod flow. + /// Authenticates to Salesforce using the OAuth 2.0 Client Credentials flow. /// - /// This method sends a client mod token request to: + /// This method sends a client credentials token request to: /// /// `{login_url}/services/oauth2/token` /// + /// # Parameters + /// + /// This method uses the following fields from `self`: + /// - `client_id` - The Connected App Client ID (required) + /// - `client_secret` - The Connected App Client Secret (required) + /// - `login_url` - The Salesforce login URL (required) + /// /// # Errors /// - /// Returns [`SalesforceAuthError`] if the OAuth client cannot be built, the HTTP - /// request fails, or Salesforce rejects the token request. + /// Returns [`SalesforceAuthError`] if: + /// - Required fields (`client_id`, `client_secret`, or `login_url`) are missing + /// - The HTTP request fails + /// - Salesforce rejects the token request + /// - The response cannot be parsed /// /// # Examples /// /// ```rust,no_run + /// use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; /// - /// use rustsf_auth::authenticate_client_credentials; - /// # async fn example() -> Result<(), rustsf_auth::SalesforceAuthError> { - /// let session = authenticate_client_credentials( + /// # async fn example() -> Result<(), SalesforceAuthError> { + /// let credentials = SalesforceCredentials::client_credentials( /// "https://login.salesforce.com", - /// "client-id", - /// "client-secret", - /// ).await?; + /// "your-client-id", + /// "your-client-secret", + /// ); /// - /// println!("{}", session.access_token); + /// let session = credentials.connect().await?; + /// println!("Access token: {}", session.access_token().await?); /// # Ok(()) /// # } /// ``` - /// - /// Configure Salesforce - /// - /// 1. Create the External Client App - /// - Navigate to Setup > External Client App Manager. - /// - Click New External Client App and enter the app name and contact email. - /// - Expand the API (Enable OAuth Settings) section: - /// - Check Enable OAuth. - /// - Check Enable Client Credentials Flow. - /// - Add the Manage user data via APIs (api) scope. Do not add refresh_token or offline_access as these are invalid for this flow. - /// - Click Create and note the Consumer Key (Client ID) and Consumer Secret. - /// - /// 2. Configure Policies and Run As User - /// - In the External Client App Manager, find your new app and click Edit. - /// - Go to the Policies tab. - /// - Under OAuth Flows and External Client App Enhancements: - /// - Ensure Enable Client Credentials Flow is checked. - /// - In the Run As field, select the integration user (a dedicated service account with necessary API permissions). - /// - Save the changes. - /// - pub(crate) async fn connect_client_credentials(&self) -> Result { - + pub async fn connect_client_credentials(&self) -> Result { let client_id = required(self.client_id.as_deref(), "client_id")?; let client_secret = required(self.client_secret.as_deref(), "client_secret")?; diff --git a/src/credentials/mod.rs b/src/credentials/mod.rs index d7682c9..ba6b214 100644 --- a/src/credentials/mod.rs +++ b/src/credentials/mod.rs @@ -1,3 +1,9 @@ +//! Credentials and authentication flow management for Salesforce. +//! +//! This module provides the core types and methods for authenticating with Salesforce +//! using various OAuth 2.0 flows, including client credentials, JWT bearer, SFDX auth URLs, +//! and existing access tokens. + use std::sync::RwLock; use std::time::Duration; use log::trace; @@ -40,30 +46,16 @@ pub enum SalesforceAuthFlow { AccessToken, } -/// Configuration for authenticating to Salesforce. +/// Credentials details for authenticating to Salesforce. /// -/// This struct provides a single, convenient way to pass mod and select -/// the authentication flow. Prefer using the constructor methods such as -/// [`SalesforceCredentials::client_credentials`], [`SalesforceCredentials::jwt_bearer`], -/// [`SalesforceCredentials::sfdx_url`], and [`SalesforceCredentials::access_token`] +/// This struct provides a single, convenient way to pass the required information for authentication +/// +/// Prefer using one of the constructor methods below instead of manually constructing the struct. +/// - [`SalesforceCredentials::client_credentials`], +/// - [`SalesforceCredentials::jwt_bearer`], +/// - [`SalesforceCredentials::sfdx_url`], +/// - [`SalesforceCredentials::access_token`] /// instead of manually constructing the struct. -/// -/// # Examples -/// -/// ```rust -/// use rustsf_auth::{SalesforceCredentials, SalesforceAuthFlow}; -/// -/// let config = SalesforceCredentials::access_token( -/// "access-token", -/// "https://example.my.salesforce.com", -/// None, -/// None, -/// None, -/// None, -/// ); -/// -/// assert_eq!(config.flow, SalesforceAuthFlow::AccessToken); -/// ``` #[derive(Debug, Clone)] pub struct SalesforceCredentials { /// The authentication flow to execute. @@ -114,20 +106,22 @@ impl SalesforceCredentials { /// # Examples /// /// ```rust,no_run - /// use rustsf_auth::SalesforceCredentials; + /// use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; /// - /// # async fn example() -> Result<(), rustsf_auth::SalesforceAuthError> { - /// let config = SalesforceCredentials::client_credentials( - /// "https://login.salesforce.com", - /// "client-id", - /// "client-secret", - /// ); - /// - /// let session = config.connect().await?; - /// println!("{}", session.access_token); - /// # Ok(()) - /// # } + /// async fn example() -> Result<(), SalesforceAuthError> { + /// let config = SalesforceCredentials::client_credentials( + /// "https://login.salesforce.com", + /// "client-id", + /// "client-secret", + /// ); + /// let session = config.connect().await?; + /// println!("{}", session.access_token().await?); + /// Ok(()) + /// } /// ``` + /// + /// # Note + /// The OAuth2.0 Web Server flow cannot be used with this method as that type is a two-step flow. pub async fn connect(self) -> Result { let token_response = self.token_response_from_flow().await?; @@ -160,11 +154,57 @@ impl SalesforceCredentials { }) } + /// Reconnects to Salesforce by re-executing the configured authentication flow. + /// + /// This internal method is used to obtain a fresh access token by running the + /// authentication flow again from scratch. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError`] if the authentication flow fails. + /// + /// # Examples + /// + /// ```rust,ignore + /// # use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; + /// # async fn example() -> Result<(), SalesforceAuthError> { + /// let credentials = SalesforceCredentials::client_credentials( + /// "https://login.salesforce.com", + /// "client-id", + /// "client-secret", + /// ); + /// let token = credentials.reconnect().await?; + /// # Ok(()) + /// # } + /// ``` pub(crate) async fn reconnect(&self) -> Result { let token_response = self.token_response_from_flow().await?; Ok(SalesforceAuthToken::from_token_response(token_response)) } + /// Executes the configured authentication flow and returns the token response. + /// + /// This internal method dispatches to the appropriate authentication method based + /// on the configured [`SalesforceAuthFlow`]. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError`] if the authentication flow fails. + /// + /// # Examples + /// + /// ```rust,ignore + /// # use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; + /// # async fn example() -> Result<(), SalesforceAuthError> { + /// let credentials = SalesforceCredentials::client_credentials( + /// "https://login.salesforce.com", + /// "client-id", + /// "client-secret", + /// ); + /// let response = credentials.token_response_from_flow().await?; + /// # Ok(()) + /// # } + /// ``` async fn token_response_from_flow(&self) -> Result { match self.flow { SalesforceAuthFlow::AccessToken => self.connect_access_token(), @@ -174,6 +214,32 @@ impl SalesforceCredentials { } } + /// Refreshes the Salesforce access token using a refresh token or by reconnecting. + /// + /// If a refresh token is available, this method uses it to obtain a new access token + /// via the OAuth 2.0 refresh token grant. Otherwise, it falls back to reconnecting + /// using the original authentication flow. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError`] if the refresh token grant fails, if required + /// fields are missing, or if the HTTP request fails. + /// + /// # Examples + /// + /// ```rust,ignore + /// # use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; + /// # async fn example() -> Result<(), SalesforceAuthError> { + /// let credentials = SalesforceCredentials::client_credentials( + /// "https://login.salesforce.com", + /// "client-id", + /// "client-secret", + /// ); + /// let token = credentials.refresh().await?; + /// println!("Access token: {}", token.access_token); + /// # Ok(()) + /// # } + /// ``` pub(crate) async fn refresh(&self) -> Result { match &self.refresh_token { @@ -209,6 +275,30 @@ impl SalesforceCredentials { } } + /// Constructs the OAuth 2.0 token endpoint URL from the login URL. + /// + /// This method builds the full token URL by appending `/services/oauth2/token` + /// to the configured login URL. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError::MissingRequiredField`] if `login_url` is not set, + /// or [`SalesforceAuthError::InvalidUrl`] if the constructed URL is invalid. + /// + /// # Examples + /// + /// ```rust,ignore + /// # use rustsf_auth::{SalesforceCredentials, SalesforceAuthError}; + /// # fn example() -> Result<(), SalesforceAuthError> { + /// let credentials = SalesforceCredentials::client_credentials( + /// "https://login.salesforce.com", + /// "client-id", + /// "client-secret", + /// ); + /// let token_url = credentials.token_url()?; + /// # Ok(()) + /// # } + /// ``` fn token_url(&self) -> Result { match &self.login_url { Some(login_url) => { @@ -222,6 +312,24 @@ impl SalesforceCredentials { } +/// Creates a configured HTTP client for Salesforce API requests. +/// +/// This function builds a [`reqwest::Client`] with no automatic redirects and a 30-second timeout. +/// +/// # Errors +/// +/// Returns [`SalesforceAuthError`] if the HTTP client cannot be built. +/// +/// # Examples +/// +/// ```rust,ignore +/// # use rustsf_auth::{SalesforceAuthError}; +/// # use rustsf_auth::credentials::http_client; +/// # fn example() -> Result<(), SalesforceAuthError> { +/// let client = http_client()?; +/// # Ok(()) +/// # } +/// ``` pub(crate) fn http_client() -> Result { Ok(Client::builder() .redirect(reqwest::redirect::Policy::none()) @@ -230,6 +338,29 @@ pub(crate) fn http_client() -> Result { } +/// Validates that a required field is present. +/// +/// # Parameters +/// +/// * `value` - The optional field value to check +/// * `field_name` - The name of the field for error reporting +/// +/// # Errors +/// +/// Returns [`SalesforceAuthError::MissingRequiredField`] if `value` is `None`. +/// +/// # Examples +/// +/// ```rust,ignore +/// # use rustsf_auth::SalesforceAuthError; +/// # use rustsf_auth::credentials::required; +/// # fn example() -> Result<(), SalesforceAuthError> { +/// let client_id = Some("my-client-id"); +/// let validated = required(client_id.as_deref(), "client_id")?; +/// assert_eq!(validated, "my-client-id"); +/// # Ok(()) +/// # } +/// ``` fn required<'a>( value: Option<&'a str>, field_name: &'static str, @@ -239,6 +370,28 @@ fn required<'a>( value.ok_or(SalesforceAuthError::MissingRequiredField(field_name)) } +/// Parses the organization ID and user ID from a Salesforce identity URL. +/// +/// Salesforce identity URLs have the format: +/// `https://login.salesforce.com/id/{org_id}/{user_id}` +/// +/// # Parameters +/// +/// * `id_url` - The optional Salesforce identity URL to parse +/// +/// # Returns +/// +/// A tuple of `(org_id, user_id)`, where both are `None` if the URL is invalid or missing. +/// +/// # Examples +/// +/// ```rust,ignore +/// # use rustsf_auth::credentials::parse_salesforce_identity_ids; +/// let url = Some("https://login.salesforce.com/id/00Dxx0000001gPLEAY/005xx000001SwiUAAS"); +/// let (org_id, user_id) = parse_salesforce_identity_ids(url); +/// assert_eq!(org_id, Some("00Dxx0000001gPLEAY".to_string())); +/// assert_eq!(user_id, Some("005xx000001SwiUAAS".to_string())); +/// ``` fn parse_salesforce_identity_ids(id_url: Option<&str>) -> (Option, Option) { let Some(id_url) = id_url else { return (None, None); diff --git a/src/credentials/web_server.rs b/src/credentials/web_server.rs index 4184e75..0501e39 100644 --- a/src/credentials/web_server.rs +++ b/src/credentials/web_server.rs @@ -49,6 +49,28 @@ impl OAuthWebService { /// The caller should call [`OAuthWebService::authorization_url`] first, open /// the returned URL in a browser, then call [`OAuthWebService::connect`] to /// wait for the callback and receive a [`SalesforceAuthSession`]. + /// + /// # Parameters + /// + /// - `login_url`: Salesforce login URL (e.g., `https://login.salesforce.com`) + /// - `client_id`: Connected app client ID + /// - `client_secret`: Optional connected app client secret + /// - `redirect_uri`: OAuth callback URL (e.g., `http://localhost:8080/callback`) + /// - `scopes`: Optional list of OAuth scopes. Defaults to `["api", "refresh_token", "offline_access"]` + /// + /// # Examples + /// + /// ```rust,no_run + /// use rustsf_auth::credentials::web_server::OAuthWebService; + /// + /// let service = OAuthWebService::new( + /// "https://login.salesforce.com", + /// "my-client-id", + /// Some("my-client-secret".to_string()), + /// "http://localhost:8080/callback", + /// None, + /// ); + /// ``` pub fn new( login_url: impl Into, client_id: impl Into, @@ -76,6 +98,34 @@ impl OAuthWebService { /// /// This method does not open a browser. The caller is responsible for opening /// the returned URL or presenting it to the user. + /// + /// # Returns + /// + /// Returns the authorization URL that the user should visit to grant access. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError::InvalidUrl`] if the login URL cannot be parsed. + /// + /// # Examples + /// + /// ```rust,no_run + /// use rustsf_auth::credentials::web_server::OAuthWebService; + /// + /// # async fn example() -> Result<(), Box> { + /// let service = OAuthWebService::new( + /// "https://login.salesforce.com", + /// "my-client-id", + /// None, + /// "http://localhost:8080/callback", + /// None, + /// ); + /// + /// let auth_url = service.authorization_url().await?; + /// println!("Visit this URL: {}", auth_url); + /// # Ok(()) + /// # } + /// ``` pub async fn authorization_url(&self) -> Result { let normalized = self.login_url.trim_end_matches('/'); let authorize_url = format!("{normalized}/services/oauth2/authorize"); @@ -102,6 +152,44 @@ impl OAuthWebService { /// /// Call [`OAuthWebService::authorization_url`] first and open that URL in a /// browser before awaiting this method. + /// + /// # Returns + /// + /// Returns a [`SalesforceAuthSession`] containing the access token and other + /// authentication details. + /// + /// # Errors + /// + /// Returns [`SalesforceAuthError`] if: + /// - The redirect URI is invalid or missing a port + /// - The TCP listener cannot be bound + /// - The OAuth callback is malformed + /// - The state parameter doesn't match + /// - Token exchange with Salesforce fails + /// + /// # Examples + /// + /// ```rust,no_run + /// use rustsf_auth::credentials::web_server::OAuthWebService; + /// + /// # async fn example() -> Result<(), Box> { + /// let service = OAuthWebService::new( + /// "https://login.salesforce.com", + /// "my-client-id", + /// Some("my-client-secret".to_string()), + /// "http://localhost:8080/callback", + /// None, + /// ); + /// + /// let auth_url = service.authorization_url().await?; + /// println!("Visit this URL: {}", auth_url); + /// // User opens the URL in a browser and authorizes + /// + /// let session = service.connect().await?; + /// println!("Access token: {}", session.access_token().await?); + /// # Ok(()) + /// # } + /// ``` pub async fn connect(&self) -> Result { let callback_url = Url::parse(&self.redirect_uri) .map_err(|source| SalesforceAuthError::InvalidUrl { @@ -144,6 +232,30 @@ impl OAuthWebService { /// /// If this method is not called, a default "Salesforce login complete" page is /// returned. + /// + /// # Parameters + /// + /// - `response`: HTML content to display in the browser after successful authentication + /// + /// # Examples + /// + /// ```rust,no_run + /// use rustsf_auth::credentials::web_server::OAuthWebService; + /// + /// let custom_html = r#" + /// + /// Success + ///

Authentication successful!

+ /// "#; + /// + /// let service = OAuthWebService::new( + /// "https://login.salesforce.com", + /// "my-client-id", + /// None, + /// "http://localhost:8080/callback", + /// None, + /// ).with_callback_response(custom_html); + /// ``` pub fn with_callback_response(mut self, response: impl Into) -> Self { self.callback_response = Some(response.into()); self diff --git a/src/lib.rs b/src/lib.rs index 6cf27ea..7bf2234 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,12 @@ +//! # RustSF Auth +//! +//! Salesforce authentication SDK for Rust, supporting the OAuth2.0 flows: +//! - [Client Credentials](crate::credentials::SalesforceCredentials#method.client_credentials) +//! - JWT, +//! - [sfdxAuthUrl](crate::credentials::SalesforceCredentials#method.sfdx_url), +//! - [Web Server](crate::credentials::web_server::OAuthWebService#method.authorization_url), +//! (this two-step flow lets a user authentiate via a browser) + use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; pub mod credentials; @@ -5,7 +14,7 @@ pub mod error; pub(crate) mod salesforce_auth_token; pub mod salesforce_token_response; -use self::error::SalesforceAuthError; +pub use self::error::SalesforceAuthError; use self::salesforce_auth_token::SalesforceAuthToken; pub use self::credentials::{SalesforceAuthFlow, SalesforceCredentials};