メインコンテンツまでスキップ
バージョン: 0.15.0 (最新)

🔗 OAuth

OAuth は Google、LINE、Twitter 向けのパブリックなブラウザー開始・コールバックルートを提供します。独立した OAuth サービスではなく、authService により合成されます。

はじめに​

各プロバイダードライバーを作成し、そのミドルウェアを Express アプリに登録してから、authService をマウントします。プロバイダーに登録するコールバック URL は、SDK ルートと同じマウントプレフィックスを含める必要があります: /auth/oauth/google/callback、/auth/oauth/line/callback、または /auth/oauth/twitter/callback。Twitter を有効にする場合は、以下のルートマウントを使用してください。そのドライバーは、プレフィックスのない Twitter SDK パスに対してのみセッションミドルウェアをインストールします。

import express from 'express';
import {drivers, services} from '@nodeblocks/backend-sdk';

const app = express();
const googleOAuthDriver = drivers.createGoogleOAuthDriver(
'google-client-id',
'google-client-secret',
'https://app.example.test/auth/oauth/google/callback',
);
const twitterOAuthDriver = drivers.createTwitterOAuthDriver(
'twitter-client-id',
'twitter-client-secret',
'https://app.example.test/auth/oauth/twitter/callback',
'replace-with-a-session-secret',
);
const lineOAuthDriver = drivers.createLineOAuthDriver(
'line-client-id',
'line-client-secret',
'https://app.example.test/auth/oauth/line/callback',
);
twitterOAuthDriver.initialize(app);
googleOAuthDriver.initialize(app);
lineOAuthDriver.initialize(app);
app.use(
'/',
services.authService(
{identities, refreshtokens, onetimetokens},
{
authSecrets: {authEncSecret: 'replace-me', authSignSecret: 'replace-me'},
oauth: {allowedRedirectOrigins: ['https://client.example.test', 'http://localhost:3000']},
},
{googleOAuthDriver, twitterOAuthDriver, lineOAuthDriver},
),
);
構成デフォルト / ソース動作効果
dataStores.identitiesすべてのコールバックで必須プロバイダーアイデンティティを検索し、oauth-signup 用に作成します。
dataStores.refreshtokensauthService で必須生成されたリフレッシュトークンを保存します。
dataStores.onetimetokensすべてのコールバックで必須生成されたログイン用ワンタイムトークンを保存します。
configuration.authSecrets開始とコールバックで必須プロバイダー state に署名し、Google/LINE コールバックで検証します。最終ワンタイムトークンにも署名します。
configuration.oauth.allowedRedirectOriginsインターフェースでは任意。デフォルトの許可リストなし。開始・コールバックのリダイレクト検証では空でない値が必要Google、LINE、Twitter のフロントエンドのリダイレクト先オリジンを許可します。未設定または空の場合はリダイレクトを拒否します。
configuration.onetimeTokenSignOptionsプロバイダー state または最終ログイントークンの生成に渡されます。authService のデフォルトは { expiresIn: '5m' }ワンタイムトークンの有効期間を制御します。
プロバイダードライバーその 2 つのルートで必須request と callback を提供します。リクエスト前に initialize(app) を呼び出します。

Google と LINE の開始 state には、fp、purpose、redirectUrl、省略可能な typeId、ユーザーエージェントが含まれます。Twitter は、プロバイダーのコールバック state を管理するドライバーに { purpose, redirectUrl, typeId } を渡します。stateQueryParameter はエクスポートされていますが、SDK はコールバッククエリをスキーマで検証しません。

authService の第 2 引数の oauth.allowedRedirectOrigins に、フロントエンドのリダイレクト先のオリジンを設定します。例えば https://client.example.test/oauth/complete には https://client.example.test を指定します。プロバイダードライバーのコールバック URL はバックエンドを指し、別途設定します。パスやワイルドカードを含まない明示的なオリジンを使用してください。照合規則は設定リファレンスと validateURL を参照してください。

開始ルートとコールバックルートは、どちらもリダイレクト先のオリジンを検証します。オリジンが未設定または空の場合は AuthenticationUnexpectedError が発生し、両方のルートが 500 に対応付けます。ルートの仕様を参照してください。

よくあるタスク​

タスク開始地点契約
Google ログインまたはサインアップを開始するgoogleOAuthFeatureパブリックな googleOAuthFeature と googleOAuthRoute。クエリ値は googleOauthSchema に従います。
LINE ログインまたはサインアップを開始するlineOAuthFeatureパブリックな lineOAuthFeature と lineOAuthRoute。クエリ値は lineOauthSchema に従います。
Twitter ログインまたはサインアップを開始するtwitterOAuthFeatureパブリックな twitterOAuthFeature と twitterOAuthRoute。クエリ値は twitterOauthSchema に従います。
プロバイダーからの戻りを処理OAuth コールバック機能state の redirectUrl を configuration.oauth.allowedRedirectOrigins に対して検証し、許可された URL に ?onetimeToken=<token> を付けてリダイレクトします。
リダイレクト先のオリジンを検証blocks.validateURL絶対 URL のオリジンが許可されていれば ok(true) を返します。オリジン未設定、不正な URL、許可されていないオリジンにはエラーを返します。

ブラウザーワークフロー​

GET /auth/oauth/google?fp=device-fingerprint&purpose=oauth-login&redirectUrl=https%3A%2F%2Fclient.example.test%2Foauth%2Fcomplete に移動します。開始ハンドラーは、まずリダイレクト URL を configuration.oauth.allowedRedirectOrigins に対して検証します。不正または許可されていない宛先は、ドライバーを呼び出す前に 400 を返します。許可された宛先では、Google ドライバーがブラウザーを Google にリダイレクトします。oauth-signup では typeId を指定してください。スキーマ上は任意ですが、未指定の場合、アイデンティティの作成は 400 で拒否されます。

絶対 URL の宛先をクエリシリアライザーに渡し、クエリパラメーターとして 1 回だけエンコードします。

const params = new URLSearchParams({
fp: 'device-fingerprint',
purpose: 'oauth-login',
redirectUrl: 'https://client.example.test/oauth/complete',
});
const loginUrl = `/auth/oauth/google?${params.toString()}`;

宛先を URLSearchParams に渡す前に encodeURIComponent を呼び出さないでください。二重エンコードすると、リクエストのクエリ解析後も URL 全体がエンコードされたままとなり、絶対 URL の検証に失敗します。SDK 0.15.0 は、最終的なトークン付きリダイレクト URL の生成時にもパーセントエンコーディングを保持します。

プロバイダー認証後、Google と LINE は state を受け取り、Twitter はドライバーが管理するコールバック state を受け取ります。state の取得後、コールバックは validateURL を使い、state の redirectUrl を configuration.oauth.allowedRedirectOrigins に対して検証します。URL は絶対 URL で、オリジンが許可されている必要があります。不正または許可されていない URL は 400、オリジンが未設定または空の場合は 500 を返します。検証に失敗すると、SDK によるアイデンティティの検査・検索・作成、トークンの生成・保存、最終リダイレクトより先に処理が停止します。Google はサインアップ時のメールアドレス重複検査より前、LINE は state の抽出後、Twitter はドライバーが state とプロフィールを返した後に検証します。

検証に成功すると、コールバックはアイデンティティを検索または作成し、ワンタイムトークンを生成・保存して、state の redirectUrl に onetimeToken を追加した 302 リダイレクトを返します。generateRedirectURL は、パス内の %20 など、指定された URL 文字列とそのパーセントエンコーディングを保持し、追加の URL デコードを行いません。リダイレクトヘルパーは常に ?onetimeToken= を追加するため、呼び出し側はそのクエリ文字列の動作を許容できるリダイレクト URL を指定する必要があります。

カスタム機能の合成​

サービスが通常の統合ポイントです。カスタムホストでは、同じストア、構成、プロバイダードライバーを合成コンテキストで渡す必要があります。機能は Express ミドルウェアではなく SDK コンポーザーです。

以下の configuration にも、上記のサービス設定と同様に authSecrets と、開始・コールバックのリダイレクト検証用の空でない oauth.allowedRedirectOrigins 許可リストが必要です。

import {partial} from 'ramda';
import {features, primitives} from '@nodeblocks/backend-sdk';

const router = primitives.defService(
partial(primitives.compose(features.googleOAuthFeature, features.googleOAuthCallbackFeature), [
{configuration, dataStores: {identities, onetimetokens}, googleOAuthDriver},
]),
);
app.use('/', router);

リファレンスマップ​

ページ目的
ブロックプロバイダー state、トークン、フィンガープリント、リダイレクトのヘルパー、および validateURL によるオリジン検証。
機能スキーマからルートへの OAuth 合成。
ルートパブリックな開始・コールバックエンドポイントの契約。
スキーマプロバイダー開始クエリの検証。

OAuth には handlers.md や validators.md ページはありません。Authentication を介して合成されます。

関連モジュール​

Authentication は、これを含むサービスとワンタイムトークンログインを提供します。Authentication サービス は構成とマウントを定義します。OAuth ドライバー は Google、Twitter、LINE のドライバーファクトリーとミドルウェアを定義します。Authentication ブロック はトークン、フィンガープリント、アイデンティティのヘルパーを提供し、共通ブロック は最終リダイレクトを提供します。