メインコンテンツまでスキップ

Webflow アプリケーションへ認証機能の追加

このガイドでは、Logto を Webflow サイトに統合する方法を紹介します。

ヒント:

サンプルプロジェクトは Webflow プロジェクトプレビュー で利用可能です。

前提条件

  1. Webflow と Logto を統合するには、Webflow の「カスタムコード」機能が必要で、少なくとも「Basic」プランが必要です。
  2. Webflow サイト。既存のサイトを使用するか、新しいサイトを作成します。

統合

Logto プロバイダーの初期化

注記:

以下の手順では、あなたの Webflow サイトが https://your-awesome-site.webflow.io で動作していると仮定します。

このステップでは、Webflow サイトにグローバルレベルのカスタムコードを追加します。Webflow では NPM がサポートされていないため、Logto SDK をインポートするために jsdelivr.com CDN サービスを使用します。

「サイト設定」ページを開き、「カスタムコード」セクションに移動します。「ヘッドコード」セクションに次のコードを追加します。

<script type="module">
// jsdelivr CDN から \`@logto/browser\` SDK をインポート
import LogtoClient from 'https://esm.run/@logto/browser';

// \`logtoClient\` インスタンスを window オブジェクトに割り当て、
// 他のページでのグローバルな使用を可能にする
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // 例: http://localhost:3001
appId: '<your-application-id>',
});
</script>

サインインの実装

詳細に入る前に、エンドユーザー体験の概要を簡単にご紹介します。サインインプロセスは次のようにシンプルにまとめられます:

  1. アプリがサインインメソッドを呼び出します。
  2. ユーザーは Logto のサインインページにリダイレクトされます。ネイティブアプリの場合は、システムブラウザが開かれます。
  3. ユーザーがサインインし、アプリ(リダイレクト URI として設定)に戻されます。

リダイレクトベースのサインインについて

  1. この認証 (Authentication) プロセスは OpenID Connect (OIDC) プロトコルに従い、Logto はユーザーのサインインを保護するために厳格なセキュリティ対策を講じています。
  2. 複数のアプリがある場合、同じアイデンティティプロバイダー (Logto) を使用できます。ユーザーがあるアプリにサインインすると、Logto は別のアプリにアクセスした際に自動的にサインインプロセスを完了します。

リダイレクトベースのサインインの理論と利点について詳しく知るには、Logto サインイン体験の説明を参照してください。


サインインリダイレクト URI を設定する

Logto コンソールのアプリケーション詳細ページに切り替えましょう。リダイレクト URI https://your-awesome-site.webflow.io/callback を追加し、「変更を保存」をクリックします。

Logto コンソールのリダイレクト URI

サインインボタンを実装する

Webflow デザイナーに戻り、ホームページに「サインイン」ボタンをドラッグアンドドロップし、後で getElementById() を使用して参照するために ID「sign-in」を割り当てます。

<script type="module">
const signInButton = document.getElementById('sign-in');
const onClickSignIn = () => logtoClient.signIn('https://your-awesome-site.webflow.io/callback');
signInButton.addEventListener('click', onClickSignIn);
</script>

リダイレクトを処理する

もう少しで完了です!最後のステップでは、https://your-awesome-site.webflow.io/callback をリダイレクト URI として使用し、これを適切に処理する必要があります。

まず、Webflow で「Callback」ページを作成し、単に「Redirecting...」という静的なテキストを配置します。次に、以下のページレベルのカスタムコードを「Callback」ページに追加します。

<script type="module">
(async () => {
// SDK メソッドを呼び出してサインインコールバックロジックを処理する
await logtoClient.handleSignInCallback(window.location.href);

// 処理が完了したらホームページにリダイレクトする
window.location.assign('https://your-awesome-site.webflow.io');
})();
</script>

サインアウトの実装

.signOut() を呼び出すと、存在する場合、メモリと localStorage 内のすべての Logto データがクリアされます。

サインアウト後に、ユーザーをあなたのウェブサイトにリダイレクトするのは素晴らしいことです。Admin Console でポストサインアウト URI の 1 つとして https://your-awesome-site.webflow.io を追加し、.signOut() を呼び出す際に URL をパラメーターとして使用しましょう。

サインアウトボタンを実装する

Webflow デザイナーに戻り、ホームページに「サインアウト」ボタンを追加します。同様に、ボタンに ID「sign-out」を割り当て、ページレベルのカスタムコードに次のコードを追加します。

const signOutButton = document.getElementById('sign-out');
const onClickSignOut = () => logtoClient.signOut('https://your-awesome-site.webflow.io');
signOutButton.addEventListener('click', onClickSignOut);

認証 (Authentication) ステータスの処理

Logto SDK では、一般的に logtoClient.isAuthenticated() メソッドを使用して認証 (Authentication) ステータスを確認できます。ユーザーがサインインしている場合、この値は true になります。そうでない場合は false になります。

Webflow サイトでも、プログラムでサインインおよびサインアウトボタンを表示および非表示にするためにこれを使用できます。次のカスタムコードを適用して、ボタンの CSS を適切に調整してください。

const isAuthenticated = await logtoClient.isAuthenticated();

signInButton.style.display = isAuthenticated ? 'none' : 'block';
signOutButton.style.display = isAuthenticated ? 'block' : 'none';

チェックポイント: Webflow サイトをテストする

次に、サイトをテストします:

  1. サイト URL をデプロイして訪問し、サインインボタンが表示されていることを確認します。
  2. サインインボタンをクリックすると、SDK がサインインプロセスを開始し、Logto のサインインページにリダイレクトされます。
  3. サインイン後、サイトに戻り、ユーザー名とサインアウトボタンが表示されます。
  4. サインアウトボタンをクリックしてサインアウトします。

ユーザー情報の取得

これらの Logto メソッドを使用して、プログラムでユーザー情報を取得できます:

  • getIdTokenClaims: ローカルの ID トークンをデコードしてユーザー情報を取得します。いくつかのクレームは利用できない場合があります。
  • fetchUserInfo: userinfo エンドポイント にリクエストを送信してユーザー情報を取得します。

重要なのは、取得できるユーザー情報のクレームは、サインイン時にユーザーが使用したスコープに依存することです。パフォーマンスとデータサイズを考慮して、ID トークンにはすべてのユーザークレームが含まれていない場合があり、いくつかのユーザークレームは userinfo エンドポイントでのみ利用可能です(以下の関連リストを参照してください)。

Logto は OIDC の スコープ (Scope) とクレーム (Claim) の規約 を使用して、ID トークンおよび OIDC userinfo エンドポイント からユーザー情報を取得するためのスコープ (Scope) とクレーム (Claim) を定義しています。「スコープ (Scope)」と「クレーム (Claim)」は、OAuth 2.0 および OpenID Connect (OIDC) 仕様の用語です。

標準の OIDC クレーム (Claim) については、ID トークンへの含有はリクエストされたスコープ (Scope) によって厳密に決定されます。拡張クレーム (Claim)(例:custom_dataorganizations)は、カスタム ID トークン 設定を通じて ID トークンに追加で表示するように構成できます。

要するに、スコープ (Scope) をリクエストすると、対応するクレーム (Claim) がユーザー情報として取得できます。たとえば、`email` スコープ (Scope) をリクエストすると、ユーザーの `email` および `email_verified` データが取得できます。

デフォルトで、Logto SDK は常に 3 つのスコープ (Scope) をリクエストします:`openid`、`profile`、および `offline_access`。 これらのデフォルトスコープ (Scope) を削除する方法はありませんが、Logto の設定時に追加のスコープ (Scope) を追加できます:

<script type="module">
// jsdelivr CDN から \`@logto/browser\` SDK をインポート
import LogtoClient from 'https://esm.run/@logto/browser';

// \`logtoClient\` インスタンスを window オブジェクトに割り当て、
// 他のページでのグローバルな使用を可能にする
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // 例: http://localhost:3001
appId: '<your-application-id>',
scopes: [
UserScope.Email,
UserScope.Phone,
UserScope.CustomData,
UserScope.Identities,
UserScope.Organizations,
],
});
</script>

こちらはサポートされているスコープと対応するクレーム (Claims) の一覧です:

標準 OIDC スコープ

openid(デフォルト)

Claim nameType説明
substringユーザーの一意の識別子

profile(デフォルト)

Claim nameType説明
namestringユーザーのフルネーム
usernamestringユーザー名
picturestringエンドユーザーのプロフィール画像の URL。この URL は画像ファイル(例:PNG、JPEG、GIF 画像ファイル)を指す必要があり、画像を含む Web ページではありません。この URL は、エンドユーザーを説明する際に表示するのに適したプロフィール写真を特に参照するべきであり、エンドユーザーが撮影した任意の写真ではありません。
created_atnumberエンドユーザーが作成された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。
updated_atnumberエンドユーザー情報が最後に更新された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。

その他の 標準クレーム (Standard Claims) には、family_namegiven_namemiddle_namenicknamepreferred_usernameprofilewebsitegenderbirthdatezoneinfolocale などがあり、これらも profile スコープに含まれます(userinfo エンドポイントをリクエストする必要はありません)。上記のクレームとの違いは、これらのクレームは値が空でない場合のみ返される点です。一方、上記のクレームは値が空の場合 null が返されます。

注記:

標準クレーム (Standard Claims) とは異なり、created_at および updated_at クレームは秒ではなくミリ秒を使用しています。

email

Claim nameType説明
emailstringユーザーのメールアドレス
email_verifiedbooleanメールアドレスが認証済みかどうか

phone

Claim nameType説明
phone_numberstringユーザーの電話番号
phone_number_verifiedboolean電話番号が認証済みかどうか

address

アドレスクレームの詳細については OpenID Connect Core 1.0 を参照してください。

備考:

(デフォルト) と記載されたスコープは常に Logto SDK によってリクエストされます。標準 OIDC スコープ下のクレーム (Claims) は、対応するスコープがリクエストされた場合、常に ID トークン (ID token) に含まれます — 無効化できません。

拡張スコープ

以下のスコープは Logto によって拡張されており、userinfo エンドポイント を通じてクレーム (Claims) を返します。これらのクレームは Console > Custom JWT を通じて ID トークン (ID token) に直接含めるよう設定することもできます。詳細は カスタム ID トークン を参照してください。

custom_data

Claim nameType説明デフォルトで ID トークンに含まれるか
custom_dataobjectユーザーのカスタムデータ

identities

Claim nameType説明デフォルトで ID トークンに含まれるか
identitiesobjectユーザーのリンク済みアイデンティティ
sso_identitiesarrayユーザーのリンク済み SSO アイデンティティ

roles

Claim nameType説明デフォルトで ID トークンに含まれるか
rolesstring[]ユーザーのロール

urn:logto:scope:organizations

Claim nameType説明デフォルトで ID トークンに含まれるか
organizationsstring[]ユーザーが所属する組織 ID
organization_dataobject[]ユーザーが所属する組織データ
注記:

これらの組織クレーム (Organization Claims) は、不透明トークン (Opaque token) を使用している場合でも userinfo エンドポイント経由で取得できます。ただし、不透明トークン (Opaque token) は組織トークン (Organization token) として組織固有リソースへのアクセスには使用できません。詳細は 不透明トークン (Opaque token) と組織 (Organizations) を参照してください。

urn:logto:scope:organization_roles

Claim nameType説明デフォルトで ID トークンに含まれるか
organization_rolesstring[]ユーザーが所属する組織ロール(<organization_id>:<role_name> 形式)

API リソース

まず 🔐 ロールベースのアクセス制御 (RBAC) を読むことをお勧めします。これにより、Logto の RBAC の基本概念と API リソースを適切に設定する方法を理解できます。

Logto クライアントを設定する

API リソースを設定したら、アプリで Logto を設定する際にそれらを追加できます:

<script type="module">
// jsdelivr CDN から \`@logto/browser\` SDK をインポート
import LogtoClient from 'https://esm.run/@logto/browser';

// \`logtoClient\` インスタンスを window オブジェクトに割り当て、
// 他のページでのグローバル使用を可能にする
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // 例: http://localhost:3001
appId: '<your-application-id>',
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'], // API リソースを追加
});
</script>

各 API リソースには独自の権限 (スコープ) があります。

例えば、https://shopping.your-app.com/api リソースには shopping:readshopping:write の権限があり、https://store.your-app.com/api リソースには store:readstore:write の権限があります。

これらの権限を要求するには、アプリで Logto を設定する際にそれらを追加できます:

<script type="module">
// jsdelivr CDN から `@logto/browser` SDK をインポート
import LogtoClient from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>',
appId: '<your-application-id>',
scopes: ['shopping:read', 'shopping:write', 'store:read', 'store:write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'],
});
</script>

スコープが API リソースとは別に定義されていることに気付くかもしれません。これは、OAuth 2.0 のリソースインジケーター が、リクエストの最終的なスコープはすべてのターゲットサービスでのすべてのスコープの直積になると指定しているためです。

したがって、上記のケースでは、Logto での定義からスコープを簡略化できます。両方の API リソースは、プレフィックスなしで readwrite スコープを持つことができます。その後、Logto の設定では:

<script type="module">
// jsdelivr CDN から `@logto/browser` SDK をインポート
import LogtoClient from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>',
appId: '<your-application-id>',
scopes: ['read', 'write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'],
});
</script>

各 API リソースは、readwrite の両方のスコープを要求します。

注記:

API リソースで定義されていないスコープを要求しても問題ありません。例えば、API リソースに email スコープが利用できなくても、email スコープを要求できます。利用できないスコープは安全に無視されます。

サインインが成功すると、Logto はユーザーのロールに応じて適切なスコープを API リソースに発行します。

API リソースのためのアクセス トークンを取得する

特定の API リソースのアクセス トークンを取得するには、getAccessToken メソッドを使用できます:

const isAuthenticated = await logtoClient.isAuthenticated();

if (isAuthenticated) {
(async () => {
const token = await logtoClient.getAccessToken();
console.log(token);
})();
}

このメソッドは、ユーザーが関連する権限を持っている場合に API リソースにアクセスするために使用できる JWT アクセス トークンを返します。現在キャッシュされているアクセス トークンが期限切れの場合、このメソッドは自動的にリフレッシュ トークンを使用して新しいアクセス トークンを取得しようとします。

組織トークンを取得する

組織 (Organization) が初めての場合は、🏢 組織 (マルチテナンシー) を読んで始めてください。

Logto クライアントを設定する際に、UserScope.Organizations スコープを追加する必要があります:

import LogtoClient, { UserScope } from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
// ...other configs
scopes: [UserScope.Organizations],
});

ユーザーがサインインしたら、ユーザーのための組織トークンを取得できます:

import { UserScope } from 'https://esm.run/@logto/browser';

const isAuthenticated = await logtoClient.isAuthenticated();

(async () => {
if (!isAuthenticated) {
return;
}
const claims = await logtoClient.getIdTokenClaims();

console.log('ID トークンのクレーム:', claims);
console.log('組織 ID:', claims.organizations);

// 少なくとも 1 つの組織があると仮定して、最初のものを取得します
const organizationId = claims.organizations[0];
const token = await logtoClient.getOrganizationToken(organizationId);

console.log('組織のアクセス トークン:', token);
})();

さらなる読み物

エンドユーザーフロー:認証 (Authentication) フロー、アカウントフロー、組織フロー コネクターの設定 認可 (Authorization)