🐏

【Rust】Googleの認可コードからユーザ情報を取得する

2024/02/27に公開

概要

Googleの認可コードをフロント側で取得し、バックエンドRustで受け取る場合の実装サンプルをメモ書きします。

前提など

  • 認可コードはフロントエンドから送られてくるものとします。フロントエンド側の実装は、Vueの例だとVue.js から Google OAuthでaccess_token,refresh_tokenを取得するの記事が参考になると思います。
  • 認可コードからtokenの取得はoauth2というクレートを使います。使用したバージョンは4.4.2です。実装についてはこちらのexampleを参考にしています。
  • tokenからユーザ情報の取得はgoogle-oauthというクレートを使います。使用したバージョンは1.10.1です。今回はAccessTokenを元にユーザ情報を取得してみます。

実装サンプル

実行基盤は、async-graphql-actix-webを使用しています。

use async_graphql::*;
use google_oauth::AsyncClient;
use oauth2::basic::BasicClient;
use oauth2::reqwest::async_http_client;
use oauth2::{
    AuthUrl, AuthorizationCode, ClientId, ClientSecret, RedirectUrl, TokenResponse, TokenUrl,
};

pub async fn validate_google_auth_code(
    auth_code: String,
    client_id: String,
    client_secret: String,
    redirect_url: String,
) -> Result<String> {
    // oauth用のクライアント
    let google_client_id = ClientId::new(client_id);
    let google_client_secret = ClientSecret::new(client_secret);
    let auth_url = AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_string());
    let token_url = TokenUrl::new("https://www.googleapis.com/oauth2/v3/token".to_string());
    let oauth_client = BasicClient::new(
        google_client_id,
        Some(google_client_secret),
        auth_url?,
        Some(token_url?),
    )
    .set_redirect_uri(RedirectUrl::new(redirect_url)?);
    // 認証コードからトークン取得
    let token_result = oauth_client
        .exchange_code(AuthorizationCode::new(auth_code))
        .request_async(async_http_client)
        .await;

    let token = match token_result {
        Ok(t) => t,
        Err(error) => return Err(Error::new(error.to_string())),
    };
    let access_token = token.access_token().secret();

    // アクセストークンからユーザ情報を取得
    let google_client = AsyncClient::new("");
    let payload_result = google_client.validate_access_token(access_token).await;
    let payload = match payload_result {
        Ok(t) => t,
        Err(error) => return Err(Error::new(error.to_string())),
    };

    Ok(payload.name.unwrap())
}

Discussion