エンベロープとAuth 0によるGraphSQL認証


This article was published on 2021-12-19 by @ The Guild Blog


誰が我々のAPIにアクセスしようとしているか確認するプロセスの認証.我々自身の解決策を構築することは難しくありえます、そして、過酷なセキュリティ問題を引き起こします.近年ではサードパーティ認証プロバイダは非常に人気となった.そのうちの一つはAuth 0です.そして、それは7.000のActiveユーザーと無制限のログインを許している例外的な自由な計画で来ます.
このガイドでは、既存のエンベロープ設定に認証を統合するために必要なすべての手順を実行します @envelop/auth0 パッケージ.

必要条件
理想的には、あなたの選択のHTTPフレームワークを使用して基本的なエンベロープのセットアップが既にあります.このガイドは、我々に基づいている graphql-helix fastify example , しかし、コードは簡単に他の例に我々のリストに転送することができますIntegrations and Examples documentation . 場合は、任意の障害物をブロックしている場合は、このページのチャットボックスを介して私たちに手を差し伸べる自由を感じる!最後の結果の完全なコードも、我々の例で利用可能です graphql-helix-auth0 fastify example .

依存関係のインストール
私たちはあなたのお気に入りのパッケージマネージャとのパッケージのセットアップにパッケージをインストールすることから始めます.
yarn install -E @envelop/auth0

エンベロープセットアップにAuth 0プラグインを追加する
import { useAuth0 } from '@envelop/auth0'

// ... other imports and code

const getEnveloped = envelop({
  plugins: [
    useSchema(schema),
    useAuth0({
      domain: 'TODO',
      audience: 'TODO',
      extendContextField: 'auth0'
    })
  ]
})

// ... server code
コードを壊しましょう.プラグインに渡すいくつかの設定オプションがあります.domain Auth 0サーバのドメインは、ユーザを認証するために通信する必要があります.次のステップでこれを記入します.audience 観衆はAPIの識別子で、我々が我々のユーザーを認証しようとしているAPIを指定するために、Auth 0に送ります.例えば、我々のAPIがホストされるならばhttp://localhost:3000/graphql , 我々は、その値を渡します.次のステップでこれを記入します.extendContextField ユーザーが首尾よく認証されたならば、認証情報はこの分野の下で文脈オブジェクトに加えられます.我々のリゾルバでは、次に我々はcontext.auth?.sub .

Auth 0 APIの設定
適切に設定するにはuseAuth0 我々が必要とするプラグインdomain and audience 値.我々は、ゼロからAuth 0を設定して、構成することによって、それらを回収するでしょう!
既にAuthor 0にサインアップしていないならば、あなたは現在それをしなければなりませんAuth0 Sign Up . 以来、あなたのgithubやGoogleアカウントにサインアップすることができます超高速!
にログインした後Auth0 dashboard そしてそこからAPIページに、APIの作成ボタンをクリックします.

APIの任意の名前を選択し、我々はEnvelop Demo この例では.
The Identifier フィールドは、GraphSQL APIのURLに設定する必要があります.私たちは、localhost上でAPIをホストしていて、ホストとポートに設定しますhttp://localhost:3000/graphql . 生産のために、代わりにそれを生産サーバのURLに設定しなければなりません.

我々は署名アルゴリズムオプションを無視することができますし、事前設定値を移動します.一旦すべてが適切に満たされるならば、我々はクリックすることができますCreate ボタン.
今、我々はすでに必要な不足している設定オプションの1つを持っているaudience , 入力したURLと同じですhttp://localhost:3000/graphql .

The domain 値は少し隠されています、しかし、我々は我々がちょうど作成したAPIの詳細ページでそれを見つけることができますTest タブ.

アカウント名と地域によって異なりますが、一般的にはこのパターンに従います
{account_name}.{region}.auth0.com
これが我々domain 設定値.
すぐに我々の封筒セットアップにこの情報を加えましょう.
import { useAuth0 } from '@envelop/auth0'

// ... other imports and code

const getEnveloped = envelop({
  plugins: [
    useSchema(schema),
    useAuth0({
      domain: '{account_name}.{region}.auth0.com',
      audience: 'http://localhost:3000/graphql',
      extendContextField: 'auth0'
    })
  ]
})
現在、エンベローププラグインの設定に必要な情報がすべてあります.しかし、ユーザーがブラウザで認証するために必要なアプリケーションをまだ設定していませんでした.
しかし、そうする前に、プラグインが何をすべきかをしていることを確認しましょう.

GraphSQLスキーマを使用して認証情報を公開する
サーバを起動する前に、認証情報を問い合わせるために、いくつかのタイプとフィールドをスキーマに追加する必要があります.
完全なコードは次のようになります.
// The quickest way of building a schema :)
import { makeExecutableSchema } from '@graphql-tools/schema'

const schema = makeExecutableSchema({
  typeDefs: /* GraphQL */ `
    """
    Describes the authentication object as provided by Auth0.
    """
    type AuthenticationInfo {
      """
      String that uniquely identifies an authenticated user.
      """
      sub: String!
    }

    type Query {
      """
      The authentication information of the request.
      """
      authInfo: AuthenticationInfo
    }
  `,
  resolvers: {
    Query: {
      authInfo(_source, _args, context) {
        return context.auth0
      }
    }
  }
})
その後、サーバーを起動することができます.ヘリックスFastifyサーバーを介して起動することができますyarn start .
C:\Users\laurin\Projects\envelop\examples\graphql-helix> yarn start
yarn run v1.22.10
$ ts-node index.ts
GraphQL server is running.
次に、http:localhost:3000/graphql .
query {
  authInfo {
    sub
  }
}

予想通り、authInfo フィールドはnull , 我々は我々の要求と一緒に任意の認証ヘッダーを渡していないとして.

Author 0トークンの生成
アクセストークンを取得するには、まず最初にAuth 0アプリケーションと認証ルートを設定する必要があります.このガイドのために、そして、複雑さを減らすために、我々は単に我々のFastify HTTP Serverへのルートを加えます<script> タグは、Autho JavaScript SDKを呼び出します(CDNを通して参照されて、それから)認証トークンを文書本体に追加します.それはまだあなたのお気に入りのフロントエンドのフレームワークを使用してオーサ0 SDKを統合できる方法を感じてください.を使用している場合.チェックアウトしてくださいnextjs-auth0 .
アプリケーションページのAuth 0インターフェイスに戻りましょう.

「アプリケーションを作成」ボタンを押し、選択した名前を入力します.Envelop Example Single Page Web ) を選択し、Single Page Web Applications アプリケーションタイプ.ボタンを押して確認します.

我々は、アプリケーションの詳細ページにリダイレクトされます.
そこから必要な最初の重要な情報はアプリケーションクライアントIDです.
我々はアプリケーションのURL設定を調整する必要がありますので、そのページでも設定タブに切り替える必要があります.当社のアプリケーションをホストされてhttp://localhost:3000 . 許可されたコールバックURLを設定し、ログアウトURLを許可し、その値にWebの起源設定を許可する必要があります.http://localhost:3000 ).
ページの末尾にある「変更を保存」ボタンで変更を保存することを忘れないでください.
次に、新しいルートを追加します.
// ... envelop setup ...

app.route({
  method: 'GET',
  url: '/',
  async handler(req, res) {
    res.header('Content-Type', 'text/html; charset=UTF-8')
    res.send(/* HTML */ `
      <!DOCTYPE html />
      <html>
        <head>
          <script src="https://cdn.auth0.com/js/auth0-spa-js/1.12/auth0-spa-js.production.js"></script>
        </head>
        <body>
          <script>
            createAuth0Client({
              domain: '{account_name}.{region}.auth0.com',
              client_id: '<client_id>',
              audience: 'http://localhost:3000/graphql'
            }).then(async (auth0) => {
              await auth0.loginWithPopup()
              const accessToken = await auth0.getTokenSilently()
              window.document.body.innerText = accessToken
            })
          </script>
        </body>
      </html>
    `)
  }
})
前に述べたように、それは空想ではない.サーバーの再起動とオープンhttp://localhost:3000/ URLは空白ページとAuth 0ログインポップアップを見るべきです.

ログイン成功後、認証トークンが空白ページに追加されます.

それをコピーして、私たちのgraphiqlインスタンスに戻ってください.

認証要求の送信
リクエストヘッダータブでは、次の形式で認証ヘッダーを指定できます.
{
  "Authorization": "Bearer <access token>"
}
その後、操作を再実行した後、我々の結果は、我々の認証情報が含まれていることがわかります!
{
  "data": {
    "authInfo": {
      "sub": "google-oauth2|101177380012777232372"
    }
  }
}


次の手順
あなたのGraphSQL APIに対する認証を首尾よく実装することについておめでとうございます.
このガイドの完全なコードはEnvelop examples .
高度な設定オプションに関する詳細情報は useAuth0 PluginHub page .
このガイドのGraphSQLスキーマでは、Auth 0認証情報を再公開します.真の登録フローについては、ユーザ情報はregister 突然変異または類似しているので、最初と最後の名前のような追加情報はデータベースの中に格納されます.
完全なユーザオブジェクトは、 useExtendContext plugin .
const getEnveloped = envelop({
  plugins: [
    useSchema(schema),
    useAuth0(auth0Config),
    useExtendContext(async (context) => {
      if (context.auth0) {
        return {
          user: await context.db.loadUserBySub(context.auth0.sub)
        }
      }
      return {}
    })
  ]
})
詳細については、簡単にあなたのGraphSQLのセットアップに追加することができますすべての他の機能についてEnvelop Docs .
我々は深く簡単にハードの問題を解決することができます新しいプラグインを追加を追加している!
ラボで調理されている別の新しいプラグインは、操作の複雑さのプラグインを選択するから計算されたスコアに基づいてサーバーに送信される操作を制限することができます.あなたが公共のGraphSQL APIを構築しているならば、あなたはこれを逃したくありません!のフィードバックをドロップすることによってプラグインを成形ヘルプDraft PR for the Operation Complexity Plugin または下記のチャットを介してお問い合わせください.私たちはあなたのフィードバックundの使用について好奇心旺盛です!