Code Monkey home page Code Monkey logo

google-oauth's Introduction

Google-Oauth

Description

Google-Oauth is a server-side verification library for Google oauth2.

Google-Oauth can help you to verify id_token or access_token which is generated from Google.

Usage (async)

1. Setup

To import Google-Oauth to your project, please add this line into your Cargo.toml.

[dependencies]
google-oauth = { version = "1" }

If you decided to use async function, please select an async runtime. Here are some options for you:

  1. tokio
  2. async-std
  3. actix-web

We use tokio in our example, and refactor our main function like this:

#[tokio::main]
// #[async_std::main] // when you use [async-std]
// #[actix_web::main] // when you use [actix-web]
async fn main() {}

2. Do Verification (id_token)

You can get your client_id from Google Admin Console (or somewhere else), and an id_token has been provided from your user. They are all string-like. Use the following code to do verification:

use google_oauth::AsyncClient;

#[tokio::main]
async fn main() {
    let client_id = "your client id";
    let id_token = "the id_token";
    
    let client = AsyncClient::new(client_id);
    /// or, if you want to set the default timeout for fetching certificates from Google, e.g, 30 seconds, you can:
    /// ```rust
    /// let client = AsyncClient::new(client_id).timeout(time::Duration::from_sec(30));
    /// ```
    
    let payload = client.validate_id_token(id_token).await.unwrap(); // In production, remember to handle this error.
    
    // When we get the payload, that mean the id_token is valid.
    // Usually we use `sub` as the identifier for our user...
    println!("Hello, I am {}", &payload.sub);
    
    // If you have multiple client ids, you can:
    let client = AsyncClient::new_with_vec(vec![client_id]);
    // The validation fails when the id_token matches NONE of the provided client ids.
}

Do verification without any client id

When no client_id is provided for AsyncClient, cliend_id will not be used when validating id_token. In this case, AsyncClient will accept all client_id. However, Google issuer (iss), expiration (exp) and JWT hash CAN NOT be skipped.

3. Do Verification (AccessToken)

Sometimes, Google will return an access_token instead of id_token. Google-Oauth still provides API for validate access_token from Google.

Note: when validating access_token, we don't matter the client_id. So if you just need to validate access_token, you can simply pass an empty client_id, just like this:

use google_oauth::AsyncClient;

#[tokio::main]
async fn main() {
    let access_token = "the access_token";

    let client = AsyncClient::new("");

    let payload = client.validate_access_token(access_token).await.unwrap(); // In production, remember to handle this error.

    // When we get the payload, that mean the id_token is valid.
    // Usually we use `sub` as the identifier for our user...
    println!("Hello, I am {}", &payload.sub);
}

Warning: the result of access_token is different from the result of id_token, although they have a same field sub.

For full example, please view ./example/async_client/

Algorithm Supported

For validating id_token, Google may use these two kinds of hash algorithm to generate JWTs:

  • RS256
  • ES256

However, I cannot find any approach to get a valid ES256 token, and as a result, I remained a unimplemented branch, and return an Err if the JWT is ES256 hashed.

Feel free to create a new issue if you have an example. PR is welcome.

Usage (blocking)

Google-Oauth also provides a blocking client. You need to enable blocking feature:

[dependencies]
google-oauth = { version = "1", features = ["blocking"] }

You can use google_oauth::Client to validate tokens:

use google_oauth::Client;

fn main() {
    let client_id = "your client id";
    let id_token = "the id_token";

    let client = Client::new(client_id);

    let payload = client.validate_id_token(id_token).unwrap();
    
    println!("Hello, I am {}", &payload.sub);
}

For full example, please view ./examples/blocking/

WebAssembly (wasm)

Google-Oauth supports wasm, feature wasm is required.

[dependencies]
google-oauth = { version = "1", features = ["wasm"] }

You can build this library with wasm-pack build --features wasm. (cargo install wasm-pack to install first.)

If you need to import wasm into your project, you can use google_oauth::Client to run async functions.

Features

  • default: enable AsyncClient.
  • blocking: enable Client.
  • wasm: disable AsyncClient and Client(blocking), enable Client (wasm).
  • reqwest-rustls: use rustls as the TLS backend of the Reqwest client

google-oauth's People

Contributors

blkmlk avatar caojen avatar jayvdb avatar mothran avatar orge-dev avatar radix avatar viniciusd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

google-oauth's Issues

Cannot parse token when picture isn't present

Hi, due to "picture" being included within the "GooglePayload" struct, the JWT validation fails when it isn't present:

panicked at 'called Result::unwrap() on an Err value: missing field picture at line 1 column 567'

The google docs also state that this property doesn't necessarily need to be present:

image

I've solved this for my codebase by simply changing the "picture" member's type to Option<String>, rather than String. This seems to work fine for me, although I'm not sure if it's the best fix.
If this is correct, it could be best to make most of the other members Option types, as google seems to make no guarantees about most of them being present.

I'm happy to PR this in if this is the best fix.

Don't fetch certs on every identity verification

It looks like right now this library is fetching the google certs on every validation, which is a shame, because with JWTs ideally verification should be instantaneous and not require hitting any network services or databases. The (unmaintained) google-signin-rs crate solved this problem with a "CachedCerts" struct which requires the user to call refresh_if_needed (implementation here). (I think that need to call refresh_if_needed is a bit silly; in this library I think it would be reasonable to just call it in validate_token).

Cache

Hi there, just want to know if can i use this on every request (Axum server) or maybe I should create the client once and re-use it in every request?

Allow multiple client IDs for token verification

I'm having a bit of an issue with authentication from native apps with multiple client IDs.

Right now you can only provide one client ID for verification. But in our case the iOS and Android and Web App all have different client IDs.

Also it would be nice to have a more detailed error message (if the claims don't match - also print their values so it's easier to track down problems).

I'm not even sure if I'm getting something wrong or trying the wrong approach here.

Braindead approach for clarification:

let client = AsyncClient::new(!vec[
        "XXXXXX1111111.apps.googleusercontent.com",
        "XXXXXX222222.apps.googleusercontent.com",
    ]);

Ways to reach you

Hi! :)
Do you have your development discord server that we can join?

Any hope for WASM support?

I would love to switch to this, if it supported WASM. I currently use my own fork of the unmaintained https://github.com/wyyerd/google-signin-rs which I had to create in order to get it to work on WASM in the cloudflare workers environment. One of the issues was that the jwt crate (at least in its default configuration?) was depending on some C algorithms from ring, so I switched it to use the jwt_compact crate, which maybe you could consider for this crate. It definitely has a much worse API than the jwt crate does, unfortunately. I have to parse the base64 RSA components and convert to num_bigint_dig::BigUInt myself and use their confusing "StrongAlg" API to do the validation.

I am not assuming you want to support this in your library, and if you want to close this ticket, please feel free. But if you do, I would happily become a user :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.