🙌

Hasura + Firebaseで実践GraphQL入門

2021/12/04に公開

こんにちは @glassmonekeyです。zenn 初記事です。
この記事はGraphQL アドベントカレンダー4 日目の記事です。

普段は趣味でFlutterでのアプリ開発に勤しんでいます。

今回は初心者ながらもその際の個人開発のバックエンドに Hasura を活用してとても便利だったのでその紹介の記事となります。
大部分を認証付きGraphQL APIサーバーを爆速で立てる。 Hasura + Firebase Authenticationを参考にさせていただきました。
この場を借りてお礼申し上げます。
 
Hasura+Firebase Authentication の組み合わせで認証付き GraphQL エンドポイントが執筆時点だと、より簡単に作れるようになってたのではまるポイント共々合わせて記事にしてみました。

また、Flutter との連携に関してはFlutter から Hasura + Firebaseで作ったGraphQL APIを活用するを参照ください。

Hasuraとは

Postgress から簡単に GraphQL エンドポイントを作成できるサービスです。
マイグレーション管理なども付属の CLI を使えば簡単にできるので、私のように Postgress に詳しくなくても扱えるのが学習コスト低めでとてもよいです。

GraphQL のクエリ自体も GUI 操作で組み立てられるので、GraphQL の入門にもオススメしたいサービスとなっております。

ちなみに無料版だと Heroku にデータベースを用意する形になります。もちろん他にホスティングしているものがあるならそれを使うこともできます。
無料だとリージョンで日本を選べないので、プロダクション環境では課金して日本リージョンで動かすなどは検討したほうが良いでしょう。

https://hasura.io/

認証機能について

認証機能は Postgress の行アクセス制限などを使ってたりするので、情報を見つけやすいことも魅力な点です。
アクセス方法は大きく以下の2点が設定できます。

また、データに対するアクセスはロールによる制御がされています。
管理トークンでアクセスしたときは admin ロール(全データの CRUD 操作が可能なロール)のよるアクセスが設定され、
JWT によるアクセス時は JWT のクレームで設定した値に応じてロールを設定できます。
詳細は公式のRoles & Session variablesをみると良いでしょう。

以下は admin ロールと user ロールを予め作った例になります。
user は partical アクセスとなっており、部分的にしか CRUD 操作できないといった設定が可能です。

Firebase との連携の際は FirebaseAuthentication から uid を X-Hasura-User-Id ヘッダーとして簡単にもらうことができるので、
uid カラムを用意してそこに一致する場合のみ操作可能にする権限設定が可能です。

Hasura と Firebase との連携

概要

今回扱う認証は Firebase Authentication の JWT を Hasura の認証に利用する方式となります。

jwtイメージ

https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html#auth-jwt

2021 年 9 月時点だと heroku を意識しなくてよくなってる点や、function を用意しなくてもよくなってる点が上記記事に加えて大きな変更点として挙げられます。

Hasuraのセットアップ

  1. プロジェクトを作ります。
    最初は無料版でいいでしょう。無料版だと日本リージョンで作れないなど注意が必要です。

  2. コンソールを開きます

3. データベースの項目に移動します。

  1. heroku からの連携をすると終わりです

アクセス制限に関してはデフォルトで HASURA_GRAPHQL_ADMIN_SECRET が設定されているはずなので
一旦は気にしなくても大丈夫です。 Env vars のところから確認できます。
これが漏れてしまうと、全テーブルに無差別でアクセスができる状態になっています。

動作確認

この段階でためしにデータを入れて GraphQL のクエリをためしてみましょう。
GUI 操作で create テーブルと insert なども可能ですがここでは割愛します。

テーブル追加とデータ追加すると Exploer から GUI 操作でクエリ操作を検証できます。
このコンソール画面では管理トークンを使った admin ロールで行います。
ユーザー権限の動作確認は x-hasura-role などを設定して擬似的にそのユーザーの権限になることもできます。 詳細はAccess control basicsに記載されています。

Firebaseのセットアップ

認証基盤としての FirebaseAuthentication のセットアップを行います。
今回は FirebaseAuthentication のみ使います。認証基盤は好きなのをご利用ください。

カスタムクレームのアップロード

Hasura にはcustom claimsという、
jwt の claims からいい感じに認証データを読み取ってくれるマッピングを設定があります。

FirebaseのJWTトークンの構成を確認する。

ちなみに Firebase Authentication の JWT をデコードすると、clams 以下は執筆時点以下のような構成です。
google sigin in してる状態なので sign_in_provider が google.com になっています。
トークンの詳細はVerify ID Tokensにも記載があるので、確認するといいでしょう。

{
  picture: プロフィールの画像パス, 
  firebase: {
    identities: {
      google.com: [],
      email: []
    },
    sign_in_provider: google.com
  },
  user_id: FirebaseAuthentication上のUID,
  aud: firebaseプロジェクト名,
  exp: 1630883599,
  iat: 1630879999,
  iss: "https://securetoken.google.com/firebaseプロジェクト名",
  sub: FirebaseAuthentication上のUID,,
  name: 名前,
  email: メールアドレス,
  email_verified: true,
  auth_time: 1630879999
}

HASURA側にアップロードする

  1. HASURA_EnvVars から New Env Var から HASURA_GRAPHQL_JWT_SECRET を追加します。

  1. 以下のような内容を記述して Add します。
    ※ プロジェクト名となっているところは各自 Firebase のプロジェクト名に読み替えてください
    json path で Firebase の設定からマッピングしてくれる claims_map のところが肝です。
    詳細は公式をご確認ください。
{
   "type": "RS256",
   "issuer": "https://securetoken.google.com/プロジェクト名",
   "jwk_url": "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com",
   "audience": "プロジェクト名",
   "claims_map": {
      "x-hasura-user-id": {
         "path": "$.user_id"
      },
      "x-hasura-default-role": "user",
      "x-hasura-allowed-roles": [
         "user"
      ]
   }
}

本来 Hasura の jwt の仕様としては以下のようにしないといけないことを
Firebase のデフォルトのクレームのまま Hasura の認証に通すことができるようになります。
なお、上記の JWT のトークンで認証する場合は一律 user 権限としてしています。
もう少し凝ったロール構成にしたい場合は Firebase 側の JWT にカスタムクレームを付与するなどしないといけません。

筆者はそこに関して検証ができていませんが、おそらくFirebaseのカスタムクレーム
の記事を参考にすると良さそうです。

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022,
  "hasura": {
     "claims": {
        "x-hasura-allowed-roles": ["editor","user", "mod"],
        "x-hasura-default-role": "user",
        "x-hasura-user-id": "1234567890",
        "x-hasura-org-id": "123",
        "x-hasura-custom": "custom-value"
     }
   }
}

Add で追加後、しばらくすると Hasura Env Vars に追加されたら作業は完了になります。

検証

アプリケーション上の動作確認は明日別記事で公開するので、この記事としては割愛させていただきます。

Flutter 側の設定はFlutter から Hasura + Firebaseで作ったGraphQL APIを活用するを参照ください。

おわりに

今回は FirebaseHasura に組み合わせで簡単に認証機能つき GraphQL エンドポイントが作れる点について解説しました。

バックエンドを用意せずに認証機能が使えるのはとても便利ですね。マイグレーション機能も内包してる点も非常に素敵です。

GraphQLPostgress の両方の初心者の自分がそこまでつまずかずに環境構築・開発ができているのは本当に良いです。

アプリケーション開発の視点でも GraphQL のおかげで型生成も容易なので、DB のデータをフロントから型安全に触ることができているのは不思議な感覚です。

ぜひみなさんも遊んでみてください。

Flutter や GraphQL のことをたまにつぶやいてたりするので、もしよかったら@glassmonekeyをフォローしていただけると喜びます。

Discussion