Firebase Authentication を使って API Gateway の認証を行う

Yuki Suwa
google-cloud-jp
Published in
20 min readDec 23, 2020

サーバーレスワークロード向けのフルマネージドな API ゲートウェイサービス “API Gateway” がベータ版としてリリースされました。API Gateway では Firebase Authentication を使ったユーザー認証をサポートしていますので、本記事ではその手順をご紹介したいと思います。

Firebase Authentication & API Gateway

はじめに

本記事は Google Cloud Japan Customer Engineer Advent Calendar 2020 の 23 日目の記事です。

API GatewayGoogle Cloud Next ’20 OnAir で発表された、フルマネージド API ゲートウェイサービスです。主にサーバーレスワークロード向けのサービスとして、Cloud Run や Cloud Functions などを呼び出すための API をかんたんに構築することができます。

API Gateway の概要 (例えば Apigee や Cloud Endpoint との違いなど)については Isobe の記事を参照いただければと思います。

API を作れたとしても、誰でも呼び出せる API だけではなく認証されたユーザーのみに制限することもできます。具体的には Google アカウントの認証はもちろん、Firebase AuthenticationAuth0Okta といった IDaaS による認証をサポートしています。

本記事では Firebase Authentication を使って API Gateway の認証を行う手順を解説したいと思います。

本記事で想定しているアーキテクチャは下図の通りです。Web アプリケーションから Firebase Authentication に対してログインし JWT を受け取ります。その JWT を使って認証付きの API をリクエストします。API のバックエンドでは Cloud Functions が動作し、様々な処理を行うことが可能です。

なお、本記事の執筆時点では API Gateway はベータ版として提供されています。一般提供開始時には本記事で紹介している機能仕様などが変更されている可能性がありますので、ご留意いただいた上お読みいただけますと幸いです。

API Gateway 事始め

まずは API Gateway の利用を開始しましょう。Google Cloud Console にて API Gateway を開き、API を有効化します。API Gateway の利用を開始するには、以下のサービスを有効化する必要があります。

  • API Gateway API
  • Service Control API
  • Service Management API

すべて有効化すると API Gateway のコンソールが表示されるようになります。

API Gateway のコンソール

Cloud Functions の関数の作成

本記事では API のバックエンドサービスとして、Cloud Functions を利用します。Cloud Functions のデプロイには以下のサービスを有効化する必要がありますので、Cloud Functions のコンソールに表示される場合は有効化してください。

  • Cloud Build API

関数名は api-backend とし、リージョンは asia-northeast1 としました。トリガーのタイプは HTTP を選択します。

関数の作成

コードは HTTP トリガーのテンプレートのままでOKです。

/**
* Responds to any HTTP request.
*
* @param {!express:Request} req HTTP request context.
* @param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
関数のコードの編集

API の作成

次に API を作成します 。表示名は Sample APIとし、API ID は sample-api としました。

API の作成

次に API Config の作成を行います。

API Config の作成

API 定義をアップロードする必要がありますので、以下の YAML ファイルをアップロードします。Open API v2 の仕様にしたがって記述します。表示名は Sample API Config としました。

# openapi2-functions.yamlswagger: '2.0'
info:
title: API_ID
description: Sample API
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/hello:
get:
summary: Send Hello World
operationId: hello
x-google-backend:
address: https://<REGION>.<PROJECT_ID>.cloudfunctions.net/<FUNCTION_NAME>
responses:
'200':
description: A successful response
schema:
type: string

太字で記述しているところは API と Cloud Functions のリソース名によって変わります。ご自身で設定した値に置き換えて記述してください。

次に進み、Gateway を作成します。表示名は Sample Gateway とします。API Gateway は現在、以下の3つのロケーションにデプロイできます。ここでは、日本に最も近い asia-east1 を選択しています。

  • 台湾 (asia-east1)
  • ベルギー (europe-west1)
  • アイオワ (us-central1)
Gateway の作成

以上で API の作成とデプロイが完了しました。cURL コマンドを実行してみるとレスポンスが返ってくるようになっていると思います。

$ curl -X GET "https://sample-gateway-xxx.de.gateway.dev/hello"
Hello, World!

Firebase Authentication の準備

次にクライアント側の準備を行いましょう。

Firebase プロジェクトを作成して Firebase Authentication の設定を行います。本記事では、プロジェクト名を Sample API Client としました。

Authentication のコンソールに移動して「始める」をクリックします。

Firebase Authentication のコンソール

本記事では Google アカウントによるシングルサインオンを利用します。

Google のログインプロバイダ設定

サンプル Web アプリケーションの起動

本記事では Web アプリケーションのテンプレートを使って、ログインおよび JWT の取得を試みたいと思います。Quick Start として GitHub で提供しているこちらを利用していきます。

こちらのリポジトリには、Firebase の各機能ごとの Quick Start がフォルダで分かれています。Firebase Authentication は auth ディレクトリ配下に用意されていますので、クローンしたあとは auth ディレクトリをルートディレクトリとして使っていきます。

$ git clone git@github.com:firebase/quickstart-js.git
$ cd quickstart-js/auth

次に Firebase CLI を使い、サンプル Web アプリケーションをローカルで起動させます。Firebase CLI が未インストールの場合は、以下のコマンドでインストールをしてください。また、別な方法でインストールをご希望の場合はこちらを参考にしてください。

# npm を利用する場合
$ npm install -g firebase-tools
# yarn を利用する場合
$ yarn global add firebase-tools

Firebase CLI のインストールが完了したら、次に Firebase CLI に Firebase プロジェクトにアクセスするための認証情報を渡します。firebase loginコマンドを実行するとどの Google アカウントを使用するか選択する画面がブラウザ上に表示されますので、手順に従って認証を行ってください。

$ firebase login

次にサンプル Web アプリケーションで使用する Firebase プロジェクトを設定します。以下のコマンドを実行すると、先ほど認証した Google アカウントで利用可能な Firebase プロジェクトが一覧できますので、その中から今回使用する Firebase プロジェクトを選択します。また、使用する Firebase プロジェクトのエイリアスも設定します。

$ firebase use --add
? Which project do you want to add? sample-api-client
? What alias do you want to use for this project? (e.g. staging) sample

これでサンプル Web アプリケーションを動かす準備が整いました。以下のコマンドを実行し、ローカルホストで起動させます。

$ firebase serve

これで http://localhost:5000 をブラウザで開くとサンプル Web アプリケーションのページが表示できるようになります。

Firebase Authentication デモ画面

この中から Google Authentication with Redirect をクリックします。遷移先の画面にて SIGN IN WITH GOOGLE のボタンをクリックし、Google アカウントでログインを行います。

Google Authentication with Redirect

ログインが成功すると、ボタンの下にユーザー情報が JSON データとして表示されます。その JSON の中から stsTokenManager.accessToken の値をコピーし、環境変数 TOKEN にセットしておきましょう。こちらは後述の cURL を使った API リクエストを行うときに使用します。

$ export TOKEN="<Web アプリから取得した JWT>"

API Gateway で Firebase Authentication の認証を有効化する

次に API の設定に認証機能を追加します。

認証の設定は API 定義(Open API)上で行います。API 作成時に用意した YAML ファイルに、Firebase Authentication を使って認証するための定義を追加します。

securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace FIREBASE_PROJECT_ID with your project ID
x-google-issuer: "https://securetoken.google.com/FIREBASE_PROJECT_ID"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"
x-google-audiences: FIREBASE_PROJECT_ID
security:
- firebase: []

認証の定義は securityDefinitions に記載します。 FIREBASE_PROJECT_ID と書かれているところは、ご自身の Firebase プロジェクトの ID に置き換えてください。なお x-google-jwks-uri はパブリックで共通の URI ですので、プロジェクトごとに書き換える必要はございません。

security はグローバルに指定するか、API 単位で指定するかのいずれかの選択が可能です。今回はグローバル(YAML 上のルート)に定義していますので、どの API に対しても認証がかかるようになっています。特定の API のセクション内に定義することで、特定の API のみに認証を加えることも可能です。例えば「管理者向けの API は管理者権限を持ったユーザーしか呼び出せない」などといったユースケースに対応することができます。

paths:
/hello:
get:
summary: Send Hello World
operationId: hello
security:
- firebase: []

API 定義ができたら、API Config を再度作成します。API 定義は YAML ファイルを再アップロード、表示名は API 作成時に作成した API Config と異なる名前にします。Gateway へのデプロイは、ドロップダウンメニューから作成済みの Gateway を選択します。

API Config の作成

数分後、デプロイが完了します。まずは JWT 無しでリクエストしてみましょう。401 Unauthorized ステータスコードが返却されます。

$ curl -v "https://sample-gateway-xxx.de.gateway.dev/hello"--- 一部省略 ---< HTTP/2 401
< content-type: application/json
< x-cloud-trace-context: e85c699601de8401e81811d0f7f85f99;o=1
< date: Wed, 23 Dec 2020 00:42:33 GMT
< server: Google Frontend
< content-length: 40
< alt-svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
<
{"message":"Jwt is missing","code":401}

JWT 付きでリクエストしてみましょう。先ほど Web アプリケーションで取得した JWT を環境変数 TOKENとして登録していました。この環境変数を Authorization Header に Bearer Token として指定します(JWT は有効期限があるので、cURL コマンドは環境変数を参照するようにした方が繰り返し試す際に JWT の差し替えが容易になります)。

$ curl -v "https://sample-gateway-xxx.de.gateway.dev/hello" -H "Authorization: Bearer $TOKEN"--- 一部省略 ---< HTTP/2 200
< content-type: text/html; charset=utf-8
< etag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"
< function-execution-id: dlrgva7xmoxu
< x-powered-by: Express
< x-cloud-trace-context: 095164445a35b9ed9ba13a13c95d847e;o=1
< x-cloud-trace-context: 095164445a35b9ed9ba13a13c95d847e;o=1
< alt-svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
< alt-svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
< date: Wed, 23 Dec 2020 00:45:31 GMT
< server: Google Frontend
< content-length: 12
<
* Connection #0 to host sample-gateway-6z6stqj2.de.gateway.dev left intact
Hello World!
* Closing connection

おまけ : 認証に Auth0 を使用する

API Gateway は Firebase Authentication だけではなく Auth0 を利用した認証もサポートしています。利用方法は非常に簡単で、API 定義の YAML の securityDefinitionssecurity を Auth0 の設定値に修正するだけです。

securityDefinitions:
auth0_jwk:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace YOUR-ACCOUNT-NAME with your Auth0 account name.
x-google-issuer: "https://YOUR-ACCOUNT-NAME.auth0.com/"
x-google-jwks_uri: "https://YOUR-ACCOUNT-NAME.auth0.com/.well-known/jwks.json"
# Optional. Replace YOUR-CLIENT-ID with your client ID
x-google-audiences: "YOUR-CLIENT-ID"
security:
- auth0_jwk: []

あとは Auth0 でログインした結果受け取ることができる JWT を Authorization Header にセットするだけです(なお Auth0 の SPA 向けの SDK で JWT 形式のトークンを得るにはこちらを参考にしてください)。

$ export TOKEN="<Auth0 から取得した JWT>"
$ curl -v "https://sample-gateway-xxx.de.gateway.dev/hello" -H "Authorization: Bearer $TOKEN"

ポイントは securityDefinitions の中に Firebase Authentication と Auth0 の両方を定義できるというところです。 security の書き方次第で、ある API は Firebase Authentication で認証を、別な API は Auth0 で認証をといった形で複数の認証プロバイダを利用できます。もちろんこの2つだけではなく、Okta や Google ログインも組み合わせることができます。ぜひ試してみてください。

まとめ

API Gateway は Cloud Run や Cloud Functions を認証付き API にする、最も簡単な方法なのではないかと思います。

また API を用意するだけではなく、API を管理する上では必要な様々な機能も備えております。また Open API v3 のサポートやセキュリティ面の強化、Apigee とのインテグレーションなど機能アップデートも予定されております(詳しくはこちらの動画をご覧ください)。今後もご期待いただければと思います。

  • モニタリング : リクエスト数やレイテンシなどがグラフで表示されるので、容易にモニタリングできます。
  • 制限 : API に Quota を設定できるので、過度な呼び出しを自動で抑制することができます。

API の構築手順も構成もシンプルにまとまりますので、ぜひ使ってみてください。

明日のアドベントカレンダー

Google Cloud Japan Customer Engineer Advent Calendar 2020 の残り日数もわずかになってきました。どの記事も非常に濃い内容になっておりますので、ぜひぜひご覧ください。

明日、24日は Sophia が担当いたします。お楽しみに!

参考

--

--

Yuki Suwa
google-cloud-jp

Customer Engineer at Google Cloud Japan. All stories are in my opinion.