8000 GitHub - makarski/gauth-rs: Rust Google Oauth2 Client Implementation · GitHub
[go: up one dir, main page]

Skip to content
makarskiPublic

About

Rust Google Oauth2 Client Implementation

Topics

Resources

Stars

21 stars

Watchers

0 watching

Forks

Latest commit

 

History

89 Commits

Folders and files

Repository files navigation

gauth

CodeScene Code Health

The library supports the following Google Auth flows:

[dependencies]
gauth = "0.10"

OAuth2

  1. Create your application in Google API Console a. Credentials > Create credentials > OAuth client ID b. Set application type to Desktop app (Google retired the Other type — Desktop app is the modern equivalent for installed-app flows) c. Enter your application name d. Download JSON configuration of the newly created application

Client implementation with defaults

use gauth::app::Auth;

#[tokio::main]
async fn main() {
    let auth_client = Auth::from_file(
        "my_credentials.json",
        vec!["https://www.googleapis.com/auth/drive"],
    )
    .unwrap();

    let token = auth_client.access_token().await.unwrap();
    println!("access token: {}", token);
}

It is also possible to make a blocking call to retrieve an access token. This may be helpful if we want to wrap the logic into a closure.

[dependencies]
gauth = { version = "0.10", features = ["app-blocking"] }
use gauth::app::Auth;

#[tokio::main]
async fn main() {
    let ga = Auth::from_file(
        "client_secret.json",
        vec!["https://www.googleapis.com/auth/drive"]
    ).unwrap();

    let closure = move || {
        // add some logic here
        ga.access_token_blocking()
    };

    let token = closure().unwrap();
    println!("token from closure: {}", token);
}

Custom app name and handler: access token will be stored in $HOME/.{app_name}/access_token.json

To assign a custom directory as access token caching, set env var value: GAUTH_TOKEN_DIR

use gauth::app::Auth;
use anyhow::Error as AnyError;

#[tokio::main]
async fn main() {
    let auth_handler = |consent_uri: String| -> Result<String, AnyError> {
        // business logic
        Ok("auth_code".to_owned())
    };

    let auth_client = Auth::from_file(
        "my_credentials.json",
        vec!["https://www.googleapis.com/auth/drive"],
    )
    .unwrap()
    .app_name("new_name")
    .handler(auth_handler);
    let token = auth_client.access_token().await.unwrap();
    println!("access token: {}", token);
}

Service Account

Follow instructions for creating a service account. After a service account key has been created, it can be used to obtain an access token.

use gauth::serv_account::ServiceAccount;

#[tokio::main]
async fn access_token() {
    let scopes = vec!["https://www.googleapis.com/auth/drive"];
    let key_path = "test_fixtures/service-account-key.json";

    let mut service_account = ServiceAccount::from_file(key_path, scopes);
    let access_token = service_account.access_token().await.unwrap();

    println!("access token {}:", access_token);
}

Loading the key from memory — useful when the credentials live in a database, an environment variable, or are fetched at runtime (no disk write needed):

use gauth::serv_account::ServiceAccount;

#[tokio::main]
async fn access_token_from_bytes(key_json: &[u8]) {
    let scopes = vec!["https://www.googleapis.com/auth/drive"];
    let mut service_account = ServiceAccount::from_bytes(key_json, scopes);
    let access_token = service_account.access_token().await.unwrap();

    println!("access token: {}", access_token);
}

JwtToken::from_bytes is also available if you only need the signed JWT and want to drive the token exchange yourself.

Token sources with expiry-aware caching (recommended)

The source feature provides the v2 token API: a TokenSource fetches one fresh token, and CachingTokenSource adds expiry-aware caching with single-flight refresh — no background task, no empty-string cold reads, and no runtime coupling (works on any executor).

[dependencies]
gauth = { version = "0.11", features = ["source"] }
use gauth::serv_account::ServiceAccount;
use gauth::source::CachingTokenSource;

let account = ServiceAccount::from_file(
    "/path/to/key.json",
    vec!["https://www.googleapis.com/auth/pubsub"],
);
let source = CachingTokenSource::new(account);

// Cached while fresh; refreshed inline (single-flight) near expiry.
let token = source.token().await?;
let header = token.authorization_header(); // "Bearer …"

Workload Identity / metadata server

On Google compute platforms (GCE, GKE with Workload Identity, Cloud Run) the metadata server issues tokens for the workload's service account — no key file involved:

use gauth::metadata::MetadataTokenSource;
use gauth::source::CachingTokenSource;

let source = CachingTokenSource::new(
    MetadataTokenSource::new()
        .with_scopes(["https://www.googleapis.com/auth/pubsub"]),
);

let token = source.token().await?;

The metadata host honors the GCE_METADATA_HOST environment variable.

Bridging sync and async code (deprecated)

Deprecated since 0.11: prefer the source API above. AsyncTokenProvider returns an empty string before its first successful refresh and refreshes on a wall-clock interval rather than token expiry. It will be removed in 0.12.

The default implementation for acquiring the access token in this library is asynchronous. However, there are scenarios where a synchronous call is necessary. For instance, asynchronous signatures can be cumbersome when used with tonic middlewares. The difficulties of integrating synchronous and asynchronous code are outlined in this GitHub issue.

To resolve this, we adopted an experimental approach by developing a token_provider package. This package includes a Watcher trait, which has been implemented for both the app and serv_account packages. Each implementation of this trait spawns a daemon that periodically polls for and caches token updates at specified intervals. As a result, tokens are consistently refreshed through an asynchronous process. The retrieval of tokens is simplified to a synchronous function that reads from the internal cache.

[dependencies]
gauth = { version = "0.10", features = ["token-watcher"] }
let service_account = ServiceAccount::from_file(&keypath, vec!["https://www.googleapis.com/auth/pubsub"]);

let tp = AsyncTokenProvider::new(service_account).with_interval(5);

// the token is updated every 5 seconds
// and cached in AsyncTokenProvider
tp.watch_updates().await;

// sync call to get the access token
let access_token = tp.access_token()?;

The full example can be found here

License

License under either or:

About

Rust Google Oauth2 Client Implementation

Topics

Resources

Stars

21 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

0