Skip to content

Instantly share code, notes, and snippets.

@awa2
Last active October 29, 2024 13:05
Show Gist options
  • Save awa2/cc7fb9d38d3f31afecf649cb32858b3a to your computer and use it in GitHub Desktop.
Save awa2/cc7fb9d38d3f31afecf649cb32858b3a to your computer and use it in GitHub Desktop.

Using Google APIs with OAuth2 101

npmのgoogleapisパッケージを利用します。 https://github.com/googleapis/google-api-nodejs-client

const { google } = require('googleapis');

 authの利用

googleapisパッケージのauthは、いくつかの認証方法を提供してくれます。

OAuth2

const OAuth2 = google.auth.OAuth2;

OAuth2クライアントの生成は次の通り。 予め、Google Cloud Platform上でOauth2クライアントを払い出しておく必要があります。

const oauth2Client = new OAuth2(
  $YOUR_CLIENT_ID,
  $YOUR_CLIENT_SECRET,
  $YOUR_REDIRECT_URL
);

REDIRECT_URLに認可コード(Authorization code)つきのリクエストが走るので、REDIRECT_URLに指定したエンドポイントで必要なパラメータを取れるようにしておきましょう。 もし、それが難しい場合にはurn:ietf:wg:oauth:2.0:oobを指定しておけば、ブラウザのタイトルバーに認可コードを返すことができます。

このoauth2clientは、いくつかの機能を持ちます。

認可要求を経由して認可コードを取得する

例えば、特定のscopeに対するOAuth2認可の要求URLは次で生成できるようになっています。

const authorizeUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: 'https://www.googleapis.com/auth/plus.me'
});

access_typeには、onlineofflineが設定できますが、違いは次の通り。

  • online ユーザがブラウザ上にいなければ、アクセストークンをリフレッシュすることができない。
  • offline ユーザがブラウザ上にいなくても、アクセストークンをリフレッシュすることができる(=Refresh Tokenが使用できる)。サーバサイド向け。

scopeはアクセスするGoogle APIのscopeを設定します。

response_typeはcode(RFC 6749)で、最初からアクセストークンを取得することはできません。 (token(RFC 6749 Code Flow)は、アクセストークンが直接返ってくる方式です。設定できるのかな?)

また、その他のパラメータとして、promptstatusがあります。

通常、Googleにおいては、リフレッシュトークンは一度しか返ってきません。 promptにconsentを割り当てると、強制的に承認が必要になります。

statusは、何らかの値をクエリ形式で保持し続けるときに使います。転送先リソースの指定、CSRF軽減、nonceの保持などに使えます。

生成されたURLは、次のようになります。

https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$YOUR_CLIENT_ID&redirect_uri=$YOUR_REDIRECT_URI&scope=$SCOPE&access_type=offline"

このURLにアクセスすると、302が返ってきて、リダイレクト先が認可画面となります。

エンドユーザーは、すでにGoogleで認証が完了している状態(セッションをもっている状態)で、このauthorizeUrlにアクセスすることで、認可を行うことができます。 つまり、この方式は 必ず1度はユーザーによるブラウザ操作を必要になります。

認可が行われると、先のREDIRECT_URIに認可コードが返ってくるので、そのコードを保持しましょう。
コードを取得するHTTPサーバの例は、次のとおりです。

const http = require('http');
const querystring = require('querystring');
const opn = require('opn');

const server = http.createServer(async (req, res) => {
  if (req.url.indexOf('/oauth2callback') > -1) {
    // acquire the code from the querystring, and close the web server.
    const qs = querystring.parse(url.parse(req.url).query);
    console.log(`Code is ${qs.code}`);
    res.end('Authentication successful! Please return to the console.');
    server.close();
    
    // Now that we have the code, use that to acquire tokens.
    const r = await oAuth2Client.getToken(qs.code);
    
    // Make sure to set the credentials on the OAuth2 client.
    oAuth2Client.setCredentials(r.tokens);
    console.info('Tokens acquired.');
    resolve(oAuth2Client);
  }
}).listen(3000, () => {
  // open the browser to the authorize url to start the workflow
  opn(authorizeUrl);
});

これで受け取ることができます。

コードからアクセストークンを取得するには

oauth2Client.getToken(code, (err,token) => {
  // callback
});

となります。

すでにリフレッシュトークンをもっている場合

oauth2Client.setCredentials({
  refresh_token: $YOUR_REFRESH_TOKEN
});

これで予め設定することが出来ます。

アクセストークンを更新する

auth.on('tokens', (tokens) => {
  auth.setCredentials(tokens);
});

これで期限が切れたトークンの更新が行なえます。

認証情報の利用

Google APIsのパッケージは、このauthインスタンスをパラメータにわたすことで、容易に認証済みリクエストを利用することができます。

const drive = google.drive({
  version: 'v3',
  auth: oauth2Client
});

簡単ですね。

Service Account

サービスアカウントとは、Google Cloud Platform内で作成することのできる実際のユーザではないアカウントです。 このサービスアカウントによるJWT(Json Web Token)方式の認証も使用することが出来ます。

OAuth2クライアントと同じく、Google Cloud Platformの画面からクライアントを払い出します。 client_id、メールアドレス、証明書フィンガープリント、そしてクレデンシャル(秘密鍵)が入ったJSONを得ることが出来ます。

const JWT = google.auth.JWT;

利用するときは、次のようになります。

const keys = require('./jwt.keys.json');
const jwtClient = new JWT(
  keys.client_email,
  null,
  keys.private_key,
  ['https://www.googleapis.com/auth/cloud-platform'],
);

トークンを取得するには、

jwtClient.authorize((err, tokens) => {
  // callback
});

認証情報は、こちらもインスタンスをパラメータにわたすだけです。

const drive = google.drive({
  version: 'v3',
  auth: jwtClient
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment