@auth-link/web 0.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +90 -1958
- package/dist/index.js +469 -155
- package/dist/index.js.map +3 -3
- package/dist/react.js +473 -152
- package/dist/react.js.map +3 -3
- package/dist/styles.css +6 -0
- package/dist/types/core.d.ts +2 -0
- package/dist/types/i18n.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/modal.d.ts +2 -0
- package/dist/types/passcode.d.ts +29 -0
- package/dist/types/react.d.ts +4 -0
- package/dist/types/types.d.ts +2 -1
- package/dist/types/view.d.ts +4 -0
- package/dist/types/vue.d.ts +4 -0
- package/dist/vue.js +485 -152
- package/dist/vue.js.map +3 -3
- package/docs/README.en.md +32 -375
- package/docs/README.ja.md +32 -375
- package/docs/README.zh-CN.md +32 -445
- package/examples/react-client.tsx +24 -0
- package/examples/vue-client.vue +31 -0
- package/package.json +6 -3
- package/docs/go-vue.en.md +0 -256
- package/docs/go-vue.ja.md +0 -256
- package/docs/go-vue.zh-CN.md +0 -260
- package/examples/vue-cms.vue +0 -109
package/docs/README.ja.md
CHANGED
|
@@ -1,405 +1,62 @@
|
|
|
1
|
-
# AuthLink Web
|
|
1
|
+
# AuthLink Web 1.1
|
|
2
2
|
|
|
3
|
-
[English](
|
|
3
|
+
[English](README.en.md) · [简体中文](README.zh-CN.md) · [日本語](README.ja.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 認証コードを直接検証
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
アプリに6桁の認証コードを直接表示します。通常の検証では、毎回の承認、認証用requestId、businessId、ポーリングは不要です。初回はQRで端末を確認し、サイトで現在のコードを検証して連携を完了します。
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
サイトのログイン → Go `/api/session` の authenticated/csrf → `csrfToken: () => session.csrf` で別 origin のクライアント設定 → bind/confirm 作成 → Go で消費・検証・DB コミット → ダイアログを閉じる → 独立した業務 API で保存済み確認結果を再検証して公開、という順序です。baseUrl は Go、authLinkOrigin は AuthLink を指し、テナントキーは Go に保持します。記事/版付き要求は独自 fetch と validateTicket を使い、SDK create は purpose のみ送ります。
|
|
12
|
-
|
|
13
|
-
## 主な機能
|
|
14
|
-
|
|
15
|
-
- ブラウザー内で生成するスマートフォン登録用 QR コード。
|
|
16
|
-
- アプリと同期し、30 秒ごとに更新される照合コード。
|
|
17
|
-
- 承認・拒否・期限切れ・エラーのイベント。
|
|
18
|
-
- React コンポーネントと hook、Vue コンポーネントと composable、フレームワーク非依存の API。
|
|
19
|
-
- **簡体字中国語を既定とする 13 言語**。コンポーネントごとに指定可能。
|
|
20
|
-
- TypeScript、独立した CSS、任意の React / Vue peer dependency。
|
|
21
|
-
|
|
22
|
-
本パッケージはブラウザー用の接続ライブラリです。サイトのバックエンド、AuthLink サービス、モバイルアプリと併用します。AuthLink はアプリ内の承認と元の端末のハードウェア証明を検証します。システムのパスキー、指紋認証、画面ロックは要求しません。
|
|
23
|
-
|
|
24
|
-
## インストール
|
|
9
|
+
画面を開く前にCMSサーバーでセッションの唯一の保留中操作を原子的に確保します。別タブから上書きさせません。ユーザーはサーバーのセッションから取得し、CSRF、業務権限、元のフォームを確認します。コードを検証し、verificationIdと元の操作を原子的に確定してから成功を返します。onVerifiedは表示更新専用です。
|
|
25
10
|
|
|
26
11
|
```sh
|
|
27
|
-
npm install @auth-link/web
|
|
12
|
+
npm install @auth-link/web@^1.1.0
|
|
28
13
|
```
|
|
29
14
|
|
|
30
|
-
対応環境:React 18.2+ / 19、Vue 3.3+、TypeScript、ESM。利用するフレームワークだけをインストールしてください。ツール環境には Node 22.13+ が必要です。
|
|
31
|
-
|
|
32
|
-
## 接続の流れ
|
|
33
|
-
|
|
34
|
-
1. サイトのバックエンドに AuthLink のテナント資格情報を設定します。
|
|
35
|
-
2. 下記の業務バックエンド(同一オリジンまたは明示的に許可した別オリジン)の作成・結果取得 API を実装します。
|
|
36
|
-
3. ユーザー操作でリクエストを作成し、取得した ticket をコンポーネントに渡します。
|
|
37
|
-
4. バックエンドが結果を検証・消費した後に確認完了を返します。
|
|
38
|
-
|
|
39
|
-
ブラウザーからこのライブラリを呼び出せますが、テナント API キーと結果の消費処理は必ずサーバー側に置きます。標準クライアントは既定の同一オリジンと、明示的に許可した別オリジンに対応します。独自の通信方式では `AuthLinkClient` を実装できますが、資格情報と検証をブラウザーに移さないでください。
|
|
40
|
-
|
|
41
|
-
## クライアント作成(既定の同一オリジン Cookie モード)
|
|
42
|
-
|
|
43
|
-
`readCsrfTokenFromYourCms` は SDK のエクスポートではなく、接続先サイトで実装する関数です。現在のログインセッションに対してバックエンドが発行した CSRF token を読み取ります。CMS は必須ではありません。ブラウザーで値を生成したり、AuthLink の API キーを返したりしないでください。
|
|
44
|
-
|
|
45
|
-
既存フレームワークの CSRF 機構を優先してください。独自に実装する場合は、サーバーで暗号学的乱数(Node の `randomBytes(32).toString('base64url')` など)を生成し、セッションに保存して HTML 属性をエスケープしたうえでページに埋め込みます。下記の `{{ csrfToken }}` はサーバーテンプレートの変数です。このページを公開キャッシュしないでください。
|
|
46
|
-
|
|
47
|
-
```html
|
|
48
|
-
<meta name="csrf-token" content="{{ csrfToken }}">
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
SDK は各リクエストで token を読み取り、`X-CSRF-Token` と同一オリジンのセッション cookie を送信します。作成 API と結果 API の両方で、バックエンドが同じセッションの token と照合し、欠落・不一致や不正なリクエスト元を拒否する必要があります。ログインやセッション変更後は最新 token を取得してください。SPA ではサイト独自の同一オリジン初期化 API から取得する方法も使えます。別のヘッダー名を使うフレームワークでは`csrfHeaderName` または独自 `AuthLinkClient` で適合します。
|
|
52
|
-
|
|
53
|
-
`authlink-client.ts` を作成します:
|
|
54
|
-
|
|
55
15
|
```ts
|
|
56
|
-
|
|
57
|
-
import { createAuthLinkClient } from '@auth-link/web';
|
|
16
|
+
import { openPasscode, createPasscodeClient } from '@auth-link/web';
|
|
58
17
|
import '@auth-link/web/styles.css';
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return token;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export const client = createAuthLinkClient({
|
|
69
|
-
baseUrl: '/api/authlink',
|
|
70
|
-
csrfToken: readCsrfTokenFromYourCms,
|
|
71
|
-
// AuthLink production API origin.
|
|
72
|
-
authLinkOrigin: 'https://api.getauthlink.com',
|
|
18
|
+
const client = createPasscodeClient({ baseUrl: '/api', csrfToken: () => csrfToken });
|
|
19
|
+
const modal = openPasscode({
|
|
20
|
+
client, expiresAt: pending.expiresAt, locale: 'zh-CN', variant: 'B',
|
|
21
|
+
// First-time enrollment only:
|
|
22
|
+
// bindingQr: pending.bindingQr, authLinkOrigin: 'https://api.getauthlink.com',
|
|
23
|
+
onVerified: result => updateUI(result.verificationId),
|
|
73
24
|
});
|
|
25
|
+
// modal.setLocale('en'); modal.setVariant('C'); modal.destroy();
|
|
74
26
|
```
|
|
75
27
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
## フロントエンドとバックエンドの別オリジン対応(0.0.2 以降)
|
|
79
|
-
|
|
80
|
-
既定は同一オリジンの `/api/authlink` です。別オリジンの業務 API に直接接続するには完全な `baseUrl` と `allowedBackendOrigins` を指定します。例:フロントエンド `https://www.example.com`、バックエンド `https://api.example.com`。サブドメインやポートが異なる場合も別オリジンです。許可リストにはパス、ワイルドカード、ユーザー名・パスワードを含めず、信頼する固定設定を使います。HTTPS が必須で、開発用 HTTP loopback(localhost / 127.0.0.1 / [::1])のみ例外です。
|
|
81
|
-
|
|
82
|
-
SDK は認証情報を読む前に接続先を検証し、リダイレクトを拒否します。`authLinkOrigin` は QR 内の AuthLink サービスオリジンの検証用で、業務 API の許可リストとは別です。
|
|
83
|
-
|
|
84
|
-
### 別オリジンの Cookie / session
|
|
85
|
-
|
|
86
|
-
汎用例の JSON 名は csrfToken ですが、Go CMS の実際の応答は `{ authenticated: true, csrf: '…' }` です。session.csrf を SDK の csrfToken コールバックに渡せばよく、バックエンドのフィールド名を変更する必要はありません。
|
|
87
|
-
|
|
88
|
-
下記の `GET /api/session` はサイトで実装する例示 API で、SDK が提供する API ではありません。ログイン session の `{ "csrfToken": "現在のtoken" }` を返し、`Cache-Control: no-store` と CORS を設定します。既存サイトの API パスに適合してください。
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { createAuthLinkClient } from '@auth-link/web';
|
|
92
|
-
|
|
93
|
-
/** /api/session is an example endpoint implemented by your application backend. */
|
|
94
|
-
export async function createSessionBackendClient(backendOrigin: string) {
|
|
95
|
-
const response = await fetch(`${backendOrigin}/api/session`, {
|
|
96
|
-
credentials: 'include', cache: 'no-store', redirect: 'error',
|
|
97
|
-
});
|
|
98
|
-
if (!response.ok) throw new Error('Session initialization failed');
|
|
99
|
-
const session: unknown = await response.json();
|
|
100
|
-
if (!session || typeof session !== 'object' || !('csrfToken' in session) ||
|
|
101
|
-
typeof session.csrfToken !== 'string' || !session.csrfToken) {
|
|
102
|
-
throw new Error('The session endpoint must return { csrfToken: string }');
|
|
103
|
-
}
|
|
104
|
-
let currentCsrfToken = session.csrfToken;
|
|
105
|
-
return {
|
|
106
|
-
client: createAuthLinkClient({
|
|
107
|
-
baseUrl: `${backendOrigin}/api/authlink`,
|
|
108
|
-
allowedBackendOrigins: [backendOrigin],
|
|
109
|
-
credentials: 'include',
|
|
110
|
-
csrfToken: () => currentCsrfToken,
|
|
111
|
-
}),
|
|
112
|
-
// Call after your application's session/token refresh; recreate on account changes.
|
|
113
|
-
updateCsrfToken(value: string) { currentCsrfToken = value; },
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
ログイン後に `await createSessionBackendClient('https://api.example.com')` を呼び、返された `client` を既存コンポーネントに渡します。CSRF token 更新時は `updateCsrfToken(newToken)` を呼びます。ログアウトやアカウント切替時は古いダイアログを閉じ、状態を再初期化します。別オリジン Cookie には `credentials: 'include'` が必要ですが、SameSite、Secure、domain/path、ブラウザーの第三者 Cookie 制限も適用されます。別オリジンと cross-site は同じではありません。cross-site Cookie には通常 `SameSite=None; Secure` が必要で、ブラウザーによっては引き続き拒否されます。
|
|
119
|
-
|
|
120
|
-
### Bearer token / JWT
|
|
121
|
-
|
|
122
|
-
サイトの既存ログイン状態を渡してください。ログイン・更新処理で `auth.accessToken` を更新すると、SDK は作成・ポーリングのたびに最新値を読み取ります。
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
import { createAuthLinkClient } from '@auth-link/web';
|
|
126
|
-
|
|
127
|
-
/** auth is your website's existing login state, updated by its login/refresh flow. */
|
|
128
|
-
export function createBearerBackendClient(backendOrigin: string, auth: { accessToken: string }) {
|
|
129
|
-
return createAuthLinkClient({
|
|
130
|
-
baseUrl: `${backendOrigin}/api/authlink`,
|
|
131
|
-
allowedBackendOrigins: [backendOrigin],
|
|
132
|
-
credentials: 'omit',
|
|
133
|
-
accessToken: () => auth.accessToken,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
これはサイト利用者のログイン token であり、AuthLink のテナント API キーではありません。SDK が `Authorization: Bearer ...` を付加します。`accessToken` 指定時は既定で `credentials: 'omit'` となり、Cookie にフォールバックせず Bearer のみで認証するバックエンドでは CSRF を省略できます。`include` / `same-origin` を明示して Cookie を併用する場合は CSRF の提供・検証も必要です。
|
|
139
|
-
|
|
140
|
-
### バックエンドの CORS
|
|
141
|
-
|
|
142
|
-
`OPTIONS` プリフライトを処理し、実リクエスト・エラー応答・session 初期化 API にも必要な CORS ヘッダーを返します。フロントエンドが `https://www.example.com` の例:
|
|
143
|
-
|
|
144
|
-
```http
|
|
145
|
-
Access-Control-Allow-Origin: https://www.example.com
|
|
146
|
-
Access-Control-Allow-Credentials: true
|
|
147
|
-
Access-Control-Allow-Methods: GET, POST, OPTIONS
|
|
148
|
-
Access-Control-Allow-Headers: Content-Type, X-CSRF-Token, Idempotency-Key, Authorization
|
|
149
|
-
Vary: Origin
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Cookie を使う場合 `Access-Control-Allow-Origin: *` は使用できません。バックエンドの許可リストと一致する Origin のみ返し、任意の値を反射しないでください。プリフライトには通常ログイン認証情報がないため、まず Origin・メソッド・ヘッダーを検証し、実リクエストで本人確認・CSRF(Cookie モード)・所有者を検証します。独自ヘッダーや CSRF ヘッダー名は `Access-Control-Allow-Headers` に追加します。SDK はサーバーの CORS 設定を代行できず、`no-cors` で結果を読めません。[MDN CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) を参照してください。
|
|
153
|
-
|
|
154
|
-
### クライアント設定
|
|
155
|
-
|
|
156
|
-
| 設定 | 説明 |
|
|
157
|
-
| --- | --- |
|
|
158
|
-
| `baseUrl` | 業務 API の接頭辞、既定 `/api/authlink`;別オリジン時は完全 URL |
|
|
159
|
-
| `allowedBackendOrigins` | 追加許可する正確な業務 API オリジンの配列 |
|
|
160
|
-
| `credentials` | 既定 `same-origin`、`accessToken` 指定時 `omit`;別オリジン Cookie は `include` |
|
|
161
|
-
| `csrfToken` | リクエストごとの同期/非同期取得関数;Cookie モードは必須 |
|
|
162
|
-
| `csrfHeaderName` | 既定 `X-CSRF-Token`、フレームワークに合わせて変更可能 |
|
|
163
|
-
| `accessToken` | サイトのログイン token 取得関数;`Bearer ` 接頭辞は付けない |
|
|
164
|
-
| `headers` | 追加 `HeadersInit`、またはそれを返す同期/非同期関数 |
|
|
165
|
-
| `authLinkOrigin` | QR 内の信頼するサービスオリジン。業務 API オリジンとは別 |
|
|
166
|
-
| `fetch` | 任意の fetch 実装;接続先検証は維持 |
|
|
167
|
-
|
|
168
|
-
追加ヘッダーは SDK 管理の `Accept`、`Content-Type`、`Authorization`、`Idempotency-Key`、設定済み CSRF ヘッダーを上書きできません(`RESERVED_HEADER`)。`accessToken` と `csrfHeaderName` を使用してください。設定型 `ClientOptions` はルートエントリーからインポートできます。
|
|
169
|
-
|
|
170
|
-
未許可オリジンは `BACKEND_ORIGIN_NOT_ALLOWED`(旧 `CMS_ORIGIN_REQUIRED` に代わる)、不正な許可設定/URL は `INVALID_BACKEND_ORIGIN` / `INVALID_BASE_URL`、token 不足は `ACCESS_TOKEN_REQUIRED` / `CSRF_REQUIRED` となります。非同期の認証情報取得にも取消しと 10 秒タイムアウトが適用されます。CORS の詳細な失敗理由は開発者ツールで確認してください。SDK では通常 `NETWORK_ERROR` になります。
|
|
171
|
-
|
|
172
|
-
## 関数でダイアログを開く(React / Vue / JavaScript)
|
|
173
|
-
|
|
174
|
-
```ts
|
|
175
|
-
import { openAuthLinkBind, openAuthLinkConfirm, requestKey } from '@auth-link/web';
|
|
176
|
-
import { client } from './authlink-client';
|
|
177
|
-
import '@auth-link/web/styles.css';
|
|
178
|
-
|
|
179
|
-
const ticket = await client.create('confirm', { idempotencyKey: requestKey() });
|
|
180
|
-
const modal = openAuthLinkConfirm({
|
|
181
|
-
ticket, client, locale: 'ja',
|
|
182
|
-
onConfirmed: result => console.log(result.requestId),
|
|
183
|
-
onClose: () => console.log('Closed'),
|
|
184
|
-
});
|
|
185
|
-
// 登録: openAuthLinkBind({ ticket: bindingTicket, client })
|
|
186
|
-
// modal.close(); modal.setLocale('en');
|
|
187
|
-
```
|
|
28
|
+
標準クライアントは現在の認証情報とCSRFを付け、CMSのPOST /api/authへ{passcode}を送信します。フォームも送る場合はclient.verifyで{form,passcode}をCMSへ送信し、サーバーで保存済み内容と照合します。テナントキーやコード生成用秘密はブラウザーへ渡しません。
|
|
188
29
|
|
|
189
|
-
|
|
30
|
+
## オプションとコールバック
|
|
190
31
|
|
|
191
|
-
|
|
32
|
+
必須はclient.verify(passcode, signal)とexpiresAt(CMS操作の期限)です。任意でlocale、variant A/B/C、初回用bindingQrとauthLinkOrigin、onVerified、onError、onClose、onExpiredを指定します。成功結果はstatus、verificationId、authenticationPolicy、expiresAtを含み、requestIdやbusinessIdは含みません。
|
|
192
33
|
|
|
34
|
+
Cookie認証ではCSRFが必須です。Bearer認証はaccessTokenとcredentials=omitを使います。別オリジンのCMSはallowedBackendOriginsを明示し、ループバック開発以外ではHTTPSを使います。
|
|
193
35
|
|
|
194
|
-
## React
|
|
36
|
+
## ReactとVue
|
|
195
37
|
|
|
196
|
-
|
|
38
|
+
Reactは同じオプションを使い、Vueはverified、error、close、expiredイベントを発行します。clientの参照を安定させてください。13言語に対応し、既定は簡体字中国語です。Aはシンプル、Bは分割、Cはコンパクト表示です。
|
|
197
39
|
|
|
198
40
|
```tsx
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
import { AuthLinkBind, AuthLinkConfirm } from '@auth-link/web/react';
|
|
204
|
-
import { client } from './authlink-client';
|
|
205
|
-
|
|
206
|
-
export function AuthLinkPanel({ mode }: { mode: Mode }) {
|
|
207
|
-
const [ticket, setTicket] = useState<Ticket | null>(null);
|
|
208
|
-
const [busy, setBusy] = useState(false);
|
|
209
|
-
const [message, setMessage] = useState('');
|
|
210
|
-
const key = useRef<string | null>(null);
|
|
211
|
-
const creating = useRef(false);
|
|
212
|
-
function finish(message: string) {
|
|
213
|
-
setTicket(null);
|
|
214
|
-
setMessage(message);
|
|
215
|
-
}
|
|
216
|
-
function showBound(requestId: string) {
|
|
217
|
-
// UI feedback only. The backend has already verified and saved the binding.
|
|
218
|
-
finish(`Phone bound (request ${requestId})`);
|
|
219
|
-
}
|
|
220
|
-
function showConfirmed(requestId: string) {
|
|
221
|
-
finish(`Confirmed (request ${requestId})`);
|
|
222
|
-
}
|
|
223
|
-
const start = async () => {
|
|
224
|
-
if (creating.current || ticket) return;
|
|
225
|
-
creating.current = true;
|
|
226
|
-
setBusy(true);
|
|
227
|
-
setMessage('');
|
|
228
|
-
try {
|
|
229
|
-
key.current ??= requestKey();
|
|
230
|
-
setTicket(await client.create(mode, { idempotencyKey: key.current }));
|
|
231
|
-
key.current = null;
|
|
232
|
-
} catch { setMessage('Request failed; retry the same creation.'); }
|
|
233
|
-
finally { creating.current = false; setBusy(false); }
|
|
234
|
-
};
|
|
235
|
-
const Component = mode === 'bind' ? AuthLinkBind : AuthLinkConfirm;
|
|
236
|
-
return <>
|
|
237
|
-
{!ticket && <button type="button" disabled={busy} onClick={() => void start()}>Start verification</button>}
|
|
238
|
-
{ticket && <Component ticket={ticket} client={client}
|
|
239
|
-
onConfirmed={result => result.purpose === 'bind' ? showBound(result.requestId) : showConfirmed(result.requestId)}
|
|
240
|
-
onClose={() => finish('Closed')}
|
|
241
|
-
onRejected={() => finish('Request rejected on the phone')}
|
|
242
|
-
onExpired={() => finish('Request expired; start again')}
|
|
243
|
-
onError={error => setMessage(error.message)} />}
|
|
244
|
-
<p role="status">{message}</p>
|
|
245
|
-
</>;
|
|
246
|
-
}
|
|
41
|
+
import { AuthLinkPasscode } from '@auth-link/web/react';
|
|
42
|
+
// Keep client stable (for example with useMemo).
|
|
43
|
+
<AuthLinkPasscode client={client} expiresAt={pending.expiresAt}
|
|
44
|
+
locale="zh-CN" variant="B" onVerified={updateUI} />
|
|
247
45
|
```
|
|
248
|
-
|
|
249
|
-
バックエンドは結果を検証・消費・保存してから `confirmed` を返します。`showBound` は権限付与や紐付け保存を行いません。通知、サイトのアカウント状態 API の再取得、管理ページへの移動などに置き換えられます。ページ再読み込み後はサーバーから状態を取得し、コールバックや localStorage を認可に使わないでください。作成失敗時には同じ冪等キーを再利用します。
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
`locale` を省略すると簡体字中国語です。日本語は `locale="ja"`、簡体字中国語は `locale="zh-CN"` を指定します。client と ticket はレンダー間で安定したオブジェクトにしてください。React エントリーは `"use client"` を保持し、SSR ではリクエストを作成しません。
|
|
253
|
-
|
|
254
|
-
## Vue
|
|
255
|
-
|
|
256
46
|
```vue
|
|
257
|
-
<script setup
|
|
258
|
-
import {
|
|
259
|
-
import type { Ticket, Confirmation } from '@auth-link/web';
|
|
260
|
-
import { client } from './authlink-client';
|
|
261
|
-
|
|
262
|
-
defineProps<{ ticket: Ticket }>();
|
|
263
|
-
function confirmed(result: Confirmation) {
|
|
264
|
-
console.log('Confirmed request:', result.requestId);
|
|
265
|
-
}
|
|
47
|
+
<script setup>
|
|
48
|
+
import { AuthLinkPasscode } from '@auth-link/web/vue';
|
|
266
49
|
</script>
|
|
267
|
-
|
|
268
50
|
<template>
|
|
269
|
-
<
|
|
270
|
-
@
|
|
271
|
-
<AuthLinkConfirm v-else :ticket="ticket" :client="client" locale="ja"
|
|
272
|
-
@confirmed="confirmed" />
|
|
51
|
+
<AuthLinkPasscode :client="client" :expires-at="pending.expiresAt"
|
|
52
|
+
locale="zh-CN" variant="B" @verified="updateUI" />
|
|
273
53
|
</template>
|
|
274
54
|
```
|
|
275
55
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
## レイアウトの選択
|
|
279
|
-
|
|
280
|
-
初期化時の `variant` で選択します。省略時は **A** です。
|
|
281
|
-
|
|
282
|
-
| 値 | デスクトップ | モバイル |
|
|
283
|
-
| --- | --- | --- |
|
|
284
|
-
| `A`(既定) | ミニマルなカードと細いコード更新バー | 中央のカード |
|
|
285
|
-
| `B` | QR と照合コードの二列表示 | 縦並び |
|
|
286
|
-
| `C` | コンパクトなカードとキャンセル操作 | セーフエリア対応のボトムシート |
|
|
287
|
-
|
|
288
|
-
```ts
|
|
289
|
-
openAuthLinkBind({ ticket, client }); // A、既定言語は簡体字中国語
|
|
290
|
-
openAuthLinkConfirm({ ticket, client, variant: 'B' });
|
|
291
|
-
// modal.setVariant('C');
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
```tsx
|
|
295
|
-
<AuthLinkBind ticket={ticket} client={client} variant="C" />
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
```vue
|
|
299
|
-
<AuthLinkConfirm :ticket="ticket" :client="client" variant="B" />
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
すべてのレイアウトで細い進捗バーと「照合コードは30秒ごとに自動更新」を表示します。通常は「スマートフォンの確認待ち」を表示し、残り30秒になったときだけオレンジ色の期限警告と 00:29 形式に切り替わります。コード変更時の短いフェードはモーション低減設定に従い、リクエスト期限は延長されません。
|
|
303
|
-
|
|
304
|
-
React / Vue では表示中にも変更でき、リクエストやポーリングは再作成されません。未対応の値は A に戻ります。B / C のキャンセル操作は閉じるアイコンと同じく表示の監視を停止し、サーバーのリクエストは拒否しません。確認成功時は自動で閉じます。閉じる操作のタッチ領域は 44px で、キーボードのフォーカス表示も維持します。
|
|
305
|
-
|
|
306
|
-
## コンポーネントの設定
|
|
307
|
-
|
|
308
|
-
| 設定 | 型 | 説明 |
|
|
309
|
-
| --- | --- | --- |
|
|
310
|
-
| `ticket` | `Ticket`、必須 | バックエンドで作成したリクエスト |
|
|
311
|
-
| `client` | `AuthLinkClient`、必須 | バックエンドの結果を取得するクライアント |
|
|
312
|
-
| `locale` | `Locale` | 既定は `zh-CN` |
|
|
313
|
-
| `variant` | `DialogVariant` | `A`(既定)、`B`、`C` |
|
|
314
|
-
| `showQr` | `boolean` | 確認画面にも QR を表示。登録画面では常に表示 |
|
|
315
|
-
| `intervalMs` | `number` | 250~10000 ミリ秒。既定は 1500 ミリ秒 |
|
|
316
|
-
| `onRefresh` | `() => void` | 期限切れ後、新規作成して ticket を更新する処理 |
|
|
317
|
-
|
|
318
|
-
| React コールバック / Vue イベント | 引数 | 意味 |
|
|
319
|
-
| --- | --- | --- |
|
|
320
|
-
| `onConfirmed` / `confirmed` | `Confirmation` | バックエンドによる検証と消費が完了 |
|
|
321
|
-
| `onRejected` / `rejected` | `Rejection` | 拒否時はダイアログを自動で閉じる |
|
|
322
|
-
| `onExpired` / `expired` | なし | 有効期限切れ |
|
|
323
|
-
| `onError` / `error` | `Error` | 通信・応答検証・コールバックのエラー |
|
|
324
|
-
|
|
325
|
-
拒否時は `{ status: 'rejected', code: 'REJECTED', requestId, purpose }` を返します。`REJECTED` は SDK の業務ステータスで、HTTP ステータスや承認証明ではありません。拒否・再試行画面は表示せず、`onClose` も通知しません。メッセージや新規作成はサイト側で処理してください。React / Vue では `onRejected` / `@rejected` で ticket を解除してコンポーネントを破棄します。ヘッドレス hook の `snapshot.status` は `rejected` のままです。
|
|
326
|
-
|
|
327
|
-
独自 UI には React の `useAuthLink(options)`、Vue の `useAuthLink(() => options)` を利用できます。返される値は `snapshot` と `retry` です。Vue の snapshot は shallow ref です。retry は既存リクエストを再開し、onRefresh はサイト側のコードで新規作成します。
|
|
328
|
-
|
|
329
|
-
## バックエンド API
|
|
330
|
-
|
|
331
|
-
既定の接頭辞は `/api/authlink` です。両 API で Cookie + 設定した CSRF ヘッダー、または Bearer token による本人確認とリクエスト所有者を検証してください。作成時は `Idempotency-Key` も送信されます。サイトのユーザー ID は検証済みセッション/token から決定します。
|
|
332
|
-
|
|
333
|
-
```ts
|
|
334
|
-
import type { Ticket, Result } from '@auth-link/web';
|
|
335
|
-
|
|
336
|
-
// POST /api/authlink/requests
|
|
337
|
-
// Body: { purpose: 'bind' | 'confirm' }
|
|
338
|
-
// Response: Ticket
|
|
339
|
-
|
|
340
|
-
// POST /api/authlink/requests/{requestId}/result
|
|
341
|
-
// Body: {}
|
|
342
|
-
// Response: Result
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
```json
|
|
346
|
-
{
|
|
347
|
-
"status": "confirmed",
|
|
348
|
-
"requestId": "<request-id>",
|
|
349
|
-
"verificationId": "<verification-id>",
|
|
350
|
-
"purpose": "confirm",
|
|
351
|
-
"authenticationPolicy": "device-presence.v1",
|
|
352
|
-
"expiresAt": "<same-expiry-as-ticket>"
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
作成 API は AuthLink の公開 ticket(`requestId`、`purpose`、`qr`、`pairingCode`、`expiresAt`、現在の `displayCode`)を返します。displayCode は `value`、`serverTime`、`validUntil`、`periodSeconds: 30` を持ちます。確認用 ticket には displayCode が必要です。
|
|
357
|
-
|
|
358
|
-
結果 API は未完了状態と最新の表示コードを返します。`new` / `pending` / `approved` / `consumed` だけでは成功イベントは発火しません。`confirmed` を返す前に、バックエンドは保存した state と消費用冪等キーで AuthLink の結果を消費し、完全な受領情報を検証して正しいセッションに記録します。requestId / verificationId による永続的な冪等処理が必要です。
|
|
359
|
-
|
|
360
|
-
## 対応言語
|
|
361
|
-
|
|
362
|
-
| Code | Language |
|
|
363
|
-
| --- | --- |
|
|
364
|
-
| `en` | English |
|
|
365
|
-
| `zh-CN` | 简体中文 (default) |
|
|
366
|
-
| `zh-TW` | 繁體中文 |
|
|
367
|
-
| `ja` | 日本語 |
|
|
368
|
-
| `bn` | বাংলা |
|
|
369
|
-
| `es` | Español |
|
|
370
|
-
| `fil` | Filipino |
|
|
371
|
-
| `hi` | हिन्दी |
|
|
372
|
-
| `id` | Bahasa Indonesia |
|
|
373
|
-
| `ms` | Bahasa Melayu |
|
|
374
|
-
| `pt` | Português |
|
|
375
|
-
| `th` | ไทย |
|
|
376
|
-
| `vi` | Tiếng Việt |
|
|
377
|
-
|
|
378
|
-
未指定・未対応の言語コードは簡体字中国語にフォールバックします。ルート要素には `lang` が設定されます。ルートエントリーの `supportedLocales` で一覧を取得できます。言語変更は表示文言だけに作用し、数字やリクエストは変更しません。ドキュメントは英語・中国語・日本語で提供します。
|
|
379
|
-
|
|
380
|
-
## スタイルとエントリー
|
|
381
|
-
|
|
382
|
-
`@auth-link/web/styles.css` を明示的に読み込みます。ダイアログは `document.body` に追加されるため、`:root` または `.authlink-dialog` で `--authlink-foreground`、`--authlink-background`、`--authlink-accent`、`--authlink-muted` を上書きします。クラス名の接頭辞は `authlink-` です。
|
|
383
|
-
|
|
384
|
-
React / Vue はダイアログの `className` に対応します。Vue は文字列・配列・オブジェクト形式の `class` も受け取り、`className` と結合します。再作成ボタンは親が渡した最新の `onRefresh` を呼び出します。
|
|
385
|
-
|
|
386
|
-
| エントリー | 内容 |
|
|
387
|
-
| --- | --- |
|
|
388
|
-
| `@auth-link/web` | クライアント、冪等キー、対応言語、型、基本 API |
|
|
389
|
-
| `@auth-link/web/react` | React コンポーネントと hook |
|
|
390
|
-
| `@auth-link/web/vue` | Vue コンポーネントと composable |
|
|
391
|
-
| `@auth-link/web/styles.css` | スタイル |
|
|
392
|
-
|
|
393
|
-
## セキュリティと有効期限
|
|
56
|
+
## 失敗と終了処理
|
|
394
57
|
|
|
395
|
-
|
|
396
|
-
- ブラウザーに生成 seed、端末秘密鍵、テナント秘密情報を渡しません。
|
|
397
|
-
- リクエストは最大 120 秒。コード更新で期限は延長されません。サービスとアプリはモバイルプロトコル 7 に対応する必要があります。
|
|
398
|
-
- サーバー時刻と単調増加時計で残り時間を計算し、通信が止まっても期限切れの数字は隠します。更新境界で短い待ち時間が生じる場合があります。
|
|
399
|
-
- アンマウントや ticket 変更で監視を中止します。インスタンス内のイベント重複防止とは別に、バックエンドで永続的な冪等処理が必要です。
|
|
400
|
-
- フロントエンドのイベントは UI 更新用です。保護 API はバックエンドの信頼できる記録で判断します。
|
|
401
|
-
- QR はローカル生成し、バックエンドの SVG を挿入しません。CSP は `img-src 'self' data:` を許可してください。
|
|
58
|
+
使用済みコードは別操作や別セッションに使えません。ログインや初回連携直後は次のコードを待ちます。PASSCODE_INVALID、PASSCODE_USED、PASSCODE_LOCKEDを成功として扱わないでください。通信結果不明時は元の冪等キーとコードを保持して再試行し、業務を二重実行しません。
|
|
402
59
|
|
|
403
|
-
|
|
60
|
+
destroy()はブラウザー要求を中止してタイマーを解除し、終了コールバックを呼びません。close()はonCloseも呼びます。画面を閉じてもサーバー処理は元に戻らず、キャンセルと保留中操作はCMS側で管理します。待機やローカル期限判定はポーリングしません。
|
|
404
61
|
|
|
405
|
-
|
|
62
|
+
旧openAuthLink / Ticket / Consumeは以前のプロトコル向けに残ります。新アプリはopenPasscode / AuthLinkPasscodeとサーバーのAuthenticate / authenticateを使います。旧連携の移行機能は提供しません。
|