feat(misskey-js): MiAuth認証機能
This commit is contained in:
parent
c530a46e54
commit
fe0ace51c7
|
@ -37,8 +37,42 @@ import * as Misskey from 'misskey-js';
|
||||||
import { api as misskeyApi } from 'misskey-js';
|
import { api as misskeyApi } from 'misskey-js';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Authenticate
|
## Authenticate (MiAuth)
|
||||||
todo
|
MiAuthでの認証に対応しています。
|
||||||
|
|
||||||
|
### Step 1: 認証URLを生成
|
||||||
|
`APIClient`クラスの`getMiAuthURL`メソッドを使用して認証URLを生成します(これは同期関数です)。生成したURLにユーザーを誘導し、認可させてください。
|
||||||
|
|
||||||
|
``` ts
|
||||||
|
const cli = new Misskey.api.APIClient({
|
||||||
|
origin: 'https://misskey.test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { url } = cli.getMiAuthURL({
|
||||||
|
name: 'My app',
|
||||||
|
callback: 'https://example.com/callback',
|
||||||
|
permission: ['read:account'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// URLに飛ばす(例)
|
||||||
|
location.href = url;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: セッションIDからアクセストークンを取得
|
||||||
|
`APIClient`クラスの`authWithMiAuth`メソッドを使用してセッションIDからアクセストークンを取得します。アクセストークンは返却されるほか、以降同一のインスタンスを利用したリクエストに自動で設定されます(この挙動は第2引数に`false`を与えることで回避できます)。
|
||||||
|
|
||||||
|
コールバックURLを指定した場合、セッションIDはURLパラメータの`session`から取得できます。
|
||||||
|
|
||||||
|
``` ts
|
||||||
|
const cli = new Misskey.api.APIClient({
|
||||||
|
origin: 'https://misskey.test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { token } = await cli.authWithMiAuth(sessionId);
|
||||||
|
|
||||||
|
// 以後、同じAPIClientを使い続ける場合はトークンが自動で設定されます
|
||||||
|
const i = await cli.request('i');
|
||||||
|
```
|
||||||
|
|
||||||
## API request
|
## API request
|
||||||
APIを利用する際は、利用するサーバーの情報とアクセストークンを与えて`APIClient`クラスのインスタンスを初期化し、そのインスタンスの`request`メソッドを呼び出してリクエストを行います。
|
APIを利用する際は、利用するサーバーの情報とアクセストークンを与えて`APIClient`クラスのインスタンスを初期化し、そのインスタンスの`request`メソッドを呼び出してリクエストを行います。
|
||||||
|
|
|
@ -394,10 +394,22 @@ class APIClient {
|
||||||
fetch?: APIClient['fetch'] | null | undefined;
|
fetch?: APIClient['fetch'] | null | undefined;
|
||||||
});
|
});
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
authWithMiAuth(sessionId: string, setToken?: boolean): Promise<MiAuthCheckResponse>;
|
||||||
|
// (undocumented)
|
||||||
credential: string | null | undefined;
|
credential: string | null | undefined;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
fetch: FetchLike;
|
fetch: FetchLike;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
getMiAuthURL(options: {
|
||||||
|
name?: string;
|
||||||
|
icon?: string;
|
||||||
|
callback?: string;
|
||||||
|
permission?: typeof permissions_2[number][];
|
||||||
|
}, sessionId?: string): {
|
||||||
|
sessionId: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
// (undocumented)
|
||||||
origin: string;
|
origin: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,6 +1134,7 @@ declare namespace entities {
|
||||||
SignupPendingResponse,
|
SignupPendingResponse,
|
||||||
SigninRequest,
|
SigninRequest,
|
||||||
SigninResponse,
|
SigninResponse,
|
||||||
|
MiAuthCheckResponse,
|
||||||
EmptyRequest,
|
EmptyRequest,
|
||||||
EmptyResponse,
|
EmptyResponse,
|
||||||
AdminMetaResponse,
|
AdminMetaResponse,
|
||||||
|
@ -2248,6 +2261,12 @@ type MetaRequest = operations['meta']['requestBody']['content']['application/jso
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MetaResponse = operations['meta']['responses']['200']['content']['application/json'];
|
type MetaResponse = operations['meta']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MiAuthCheckResponse = {
|
||||||
|
token: string;
|
||||||
|
user: UserDetailedNotMe;
|
||||||
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['content']['application/json'];
|
type MiauthGenTokenRequest = operations['miauth___gen-token']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
@ -3110,6 +3129,7 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['
|
||||||
|
|
||||||
// Warnings were encountered during analysis:
|
// Warnings were encountered during analysis:
|
||||||
//
|
//
|
||||||
|
// src/api.ts:91:3 - (ae-forgotten-export) The symbol "permissions_2" needs to be exported by the entry point index.d.ts
|
||||||
// src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
|
@ -38,26 +38,28 @@
|
||||||
"@swc/jest": "0.2.31",
|
"@swc/jest": "0.2.31",
|
||||||
"@types/jest": "29.5.12",
|
"@types/jest": "29.5.12",
|
||||||
"@types/node": "20.11.22",
|
"@types/node": "20.11.22",
|
||||||
|
"@types/uuid": "9.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "7.1.0",
|
"@typescript-eslint/eslint-plugin": "7.1.0",
|
||||||
"@typescript-eslint/parser": "7.1.0",
|
"@typescript-eslint/parser": "7.1.0",
|
||||||
|
"esbuild": "0.19.11",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
|
"execa": "8.0.1",
|
||||||
|
"glob": "10.3.10",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-fetch-mock": "3.0.3",
|
"jest-fetch-mock": "3.0.3",
|
||||||
"jest-websocket-mock": "2.5.0",
|
"jest-websocket-mock": "2.5.0",
|
||||||
"mock-socket": "9.3.1",
|
"mock-socket": "9.3.1",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"nodemon": "3.1.0",
|
"nodemon": "3.1.0",
|
||||||
"execa": "8.0.1",
|
|
||||||
"tsd": "0.30.7",
|
"tsd": "0.30.7",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3"
|
||||||
"esbuild": "0.19.11",
|
|
||||||
"glob": "10.3.10"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"built"
|
"built"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eventemitter3": "5.0.1",
|
"eventemitter3": "5.0.1",
|
||||||
"reconnecting-websocket": "4.4.0"
|
"reconnecting-websocket": "4.4.0",
|
||||||
|
"uuid": "9.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import './autogen/apiClientJSDoc.js';
|
import './autogen/apiClientJSDoc.js';
|
||||||
|
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { SwitchCaseResponseType } from './api.types.js';
|
import { SwitchCaseResponseType } from './api.types.js';
|
||||||
|
import { permissions } from './consts.js';
|
||||||
import type { Endpoints } from './api.types.js';
|
import type { Endpoints } from './api.types.js';
|
||||||
|
import type { MiAuthCheckResponse } from './entities.js';
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
SwitchCaseResponseType,
|
SwitchCaseResponseType,
|
||||||
|
@ -80,4 +83,55 @@ export class APIClient {
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getMiAuthURL(options: {
|
||||||
|
name?: string;
|
||||||
|
icon?: string;
|
||||||
|
callback?: string;
|
||||||
|
permission?: typeof permissions[number][];
|
||||||
|
}, sessionId?: string): {
|
||||||
|
sessionId: string;
|
||||||
|
url: string;
|
||||||
|
} {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (options.name) params.set('name', options.name);
|
||||||
|
if (options.icon) params.set('icon', options.icon);
|
||||||
|
if (options.callback) params.set('callback', options.callback);
|
||||||
|
if (options.permission) params.set('permission', options.permission.join(','));
|
||||||
|
|
||||||
|
const _sessionId = sessionId ?? uuid();
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessionId: _sessionId,
|
||||||
|
url: `${this.origin}/miauth/${_sessionId}?${params.toString()}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public authWithMiAuth(sessionId: string, setToken = true): Promise<MiAuthCheckResponse> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.fetch(`${this.origin}/api/miauth/${sessionId}/check`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
credentials: 'omit',
|
||||||
|
cache: 'no-cache',
|
||||||
|
}).then(async (res) => {
|
||||||
|
const body = res.status === 204 ? null : await res.json();
|
||||||
|
|
||||||
|
if (res.status === 200 && body) {
|
||||||
|
if (setToken) {
|
||||||
|
this.credential = body.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(body as MiAuthCheckResponse);
|
||||||
|
} else {
|
||||||
|
reject({
|
||||||
|
[MK_API_ERROR]: true,
|
||||||
|
...body.error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,3 +221,8 @@ export type SigninResponse = {
|
||||||
id: User['id'],
|
id: User['id'],
|
||||||
i: string,
|
i: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MiAuthCheckResponse = {
|
||||||
|
token: string,
|
||||||
|
user: UserDetailedNotMe,
|
||||||
|
};
|
||||||
|
|
|
@ -1098,6 +1098,9 @@ importers:
|
||||||
reconnecting-websocket:
|
reconnecting-websocket:
|
||||||
specifier: 4.4.0
|
specifier: 4.4.0
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
|
uuid:
|
||||||
|
specifier: 9.0.1
|
||||||
|
version: 9.0.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@microsoft/api-extractor':
|
'@microsoft/api-extractor':
|
||||||
specifier: 7.39.1
|
specifier: 7.39.1
|
||||||
|
@ -1114,6 +1117,9 @@ importers:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: 20.11.22
|
specifier: 20.11.22
|
||||||
version: 20.11.22
|
version: 20.11.22
|
||||||
|
'@types/uuid':
|
||||||
|
specifier: 9.0.8
|
||||||
|
version: 9.0.8
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: 7.1.0
|
specifier: 7.1.0
|
||||||
version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
|
version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
|
||||||
|
|
Loading…
Reference in New Issue