- 印刷する
- PDF
OAuth2.0 Node.js の構築
- 印刷する
- PDF
Classic/VPC環境で利用できます。
Node.jsベースの OAuth2.0 Serverの基本的な構築方法について説明します。ガイドを参照し、OAuth2.0サーバが実装されていないサービスで既存の会員/認証システムと統合できます。
プロジェクト設定
プロジェクトの設定方法について説明します。
使用バージョン
使用バージョン情報は次の通りです。
- Node.js Latest LTS(2023年10月10日現在)
- node: 18.18.0
- npm: 9.8.1
使用ライブラリ
使用ライブラリ情報は次の通りです。
- express
- node-oauth2-server
- https://github.com/oauthjs/node-oauth2-server
npm install --save node-oauth2-server
- https://github.com/oauthjs/node-oauth2-server
詳細は https://oauth2-server.readthedocs.io/en/latestで確認でき、当該ライブラリを使った公式例は https://github.com/14gasher/oauth-exampleで確認できます。
構築ガイドの範囲
構築ガイドでは簡単なログインページを通して例を説明します。実際のサービス実装時、既存のログインページを次の OAuth2.0 Login APIと統合して開発します。
暗号化アルゴリズム、トークン作成アルゴリズムなどは各サービスポリシーに従って開発し、このガイドの範囲を超えるため当該領域はコメントでご案内します。
node-oauth2-server
node-oauth2-serverは事前に定義されたモデル(*OAuth2.0過程で必要な機能の明細)を実装し、認証(authenticate)、認可(authorize)、トークン(token)の3つの機能を呼び出すことで、実装された Modelのロジックに合わせて機能を提供します。
OAuth2.0に必要な機能が Modelを通して抽象化されており、その内容を実装して注入することで簡単に認証/認可/トークン発行の機能を使用できます。
提供機能
提供する機能は、次の通りです。
機能 | 説明 |
---|---|
認証(authenticate) | 発行されたトークンに基づき、API入力で認証処理を提供 |
認可(authorize) | code、passwordなどの方法で認可機能を提供 |
トークン(token) | 認可されたユーザーに対して Tokenの発行および保存機能を提供 |
ライブラリ Modelリスト
B2B PRISM Live Studio OAuth2.0の連携過程では Authorization Code/Refresh Token Grantのみを必要としており、Scopeの機能は提供していません。
PRISM OAuth2.0に必要な Modelリスト
ここで扱う Modelリストは、次の通りです。
全 Modelリストは以下をご参照ください。
機能 | 説明 |
---|---|
generateAccessToken | Access Tokenを作成するロジックを担当 |
generateRefreshToken | Refresh Tokenを作成するロジックを担当 |
generateAuthorizationCode | 認可過程で使用される Authorization Codeを作成するロジックを担当 |
getAccessToken | Token発行段階で保存されている Access Tokenを取得して検証するために使用 |
getRefreshToken | Token発行段階で保存されている Refresh Tokenを取得して検証するために使用 |
getAuthorizationCode | Authorization段階で保存されている Authorization Codeを取得して検証するために使用 |
getClient | Client情報(Client ID、Client Secret、Redirect URI)を取得するために使用 |
saveToken | Token発行段階で作成されたトークンを保存 |
saveAuthorizationCode | Authorization段階で作成された Authorization Codeを保存 |
それぞれのロールと機能については、実際の実装例をご参照ください。各モデルの最新の詳細情報などはこちらでご確認いただけます。
Modelの実装において Promiseを使った方法や async-await、callbackなどの方法がありますが、例では Promiseを使った方法で実装します。以下のサンプルコードをご確認ください。
const model = {
// We support returning promises.
getAccessToken: function() {
return new Promise('works!');
},
// Or, calling a Node-style callback.
getAuthorizationCode: function(done) {
done(null, 'works!');
},
// Or, using generators.
getClient: function*() {
yield somethingAsync();
return 'works!';
},
// Or, async/wait (using Babel).
getUser: async function() {
await somethingAsync();
return 'works!';
}
};
const OAuth2Server = require('oauth2-server');
let oauth = new OAuth2Server({model: model});
1. OAuth2.0 Login API(Authorization Code発行 API)
Authorization Code発行機能のために実装すべき Modelは、次の通りです。
generateAuthorizationCode
この機能はオプション(Optional)です。実装しない場合、40文字の codeが自動的に作成されます。独自の発行アルゴリズムが必要な場合は、直接実装します。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
client | Object |
|
user | Object | Access Token/Refresh Tokenを作成する User情報が含まれている |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
String(Authorization Code値)タイプで返されます。
Example Code
generateAuthorizationCodeのサンプルコードは、次の通りです。
{
generateAuthorizationCode: function(client, user) {
// AccessToken、RefreshTokenを作成する独自のロジックを作成
return new Promise(accessToken);
}
}
getClient
Client ID、Client Secretの情報で、Redirect URI、Token Lifetime情報を取得する機能です。実装によっては、DBなどで情報を照会して返すことができます。返された情報は OAuth2Serverの各機能内で Code/Token発行などに使用されます。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
clientId | String | 認証/認可を処理する Clientの Client ID |
clientSecret | String | 認証/認可を処理する Clientの Client Secret |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
client | Object | Access Token/Refresh Tokenを作成する Client情報が含まれている Object |
client.id | String | 認証/認可を処理する Clientの Client ID |
[client.redirectUris] | Array<String> | 当該 Clientの Redirect URIの配列で、その URIに存在する Redirect URIのみ処理が可能 |
[client.accessTokenLifetime] | Number | Access Tokenの期限切れ時間(秒) |
[client.refreshTokenLifetime] | Number | Refresh Tokenの期限切れ時間(秒) |
Example Code
generateAuthorizationCodeのサンプルコードは、次の通りです。
{
getClient: function(clientId, clientSecret) {
// DBなどから情報を取得し、client Objectを作成して返す
return new Promise(client);
}
}
saveAuthorizationCode
generateAuthorizationCodeで作成された Authorization Codeを保存する役割をします。実装によっては、DBまたは In Memory Storageに保存できます。保存された Authorization Codeを Tokenの発行時に getAuthorizationCode Modelから取り出し、有効性を検証できます。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
code | Object | 保存する Code |
code.authorizationCode | String | Authorization Code |
code.expiresAt | Date | 期限切れ時間 |
code.redirectUri | String | 発行された Authorization Codeに使用される Redirect URI |
client | Object | 発行された Authorization Codeの Client情報 |
user | Object | 発行された Authorization Codeの User情報 |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
code | Object | 保存する Code |
code.authorizationCode | String | Authorization Code |
code.expiresAt | Date | 期限切れ時間 |
code.redirectUri | String | 発行された Authorization Codeに使用される Redirect URI |
code.client | Object | 発行された Authorization Codeの Client情報 |
code.client.id | String | 発行された Authorization Codeの Client ID情報 |
code.user | Object | 発行された Authorization Codeの User情報 |
OAuth2.0 Login API(Authorization Code発行 API)例
authenticateのサンプルコードは、次の通りです。
const oauth = new OAuth2Server({model: ...}); // 先に実装された Model Objectを転送
function authorizeHandler(options) {
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
return oauth.authorize(request, response, options) // oauth.authorizeを呼び出すことで先に実装した Model が内部的に呼び出され、authorization codeを発行
.then(function(code) {
res.locals.oauth = {code: code};
next();
})
.catch(function(err) {
// handle error condition
});
}
}
2. Token発行 API
前段階で発行された Authorization Codeを Access Token/Refresh Tokenと交換/保存する機能を提供します。または、Refresh Tokenを通じて新しい Access Tokenを発行できます。
Token発行機能のために実装すべき Modelは、次の通りです。
generateAccessToken/generateRefreshToken
この機能はオプション(Optional)です。実装しない場合、40文字のトークンが自動的に作成されます。独自のトークン発行アルゴリズムが必要な場合は、直接実装します。2つのモデルは同じ明細を示しています。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
client | Object |
|
user | Object |
|
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
String(Access Token、Refresh Token値)タイプで返されます。
Example Code
generateAccessTokenのサンプルコードは、次の通りです。
{
generateAccessToken: function(client, user) {
// AccessToken、RefreshTokenを作成する独自のロジックを作成してください。
return new Promise(accessToken);
}
}
getRefreshToken
ユーザーから渡された Refresh Tokenが実際に存在する Refresh Tokenであるかを照会する目的で使用されます。
DBなどで Refresh Tokenを照会できます。Refresh Tokenが検証された後、Grant Refresh Tokenの Token発行手続きが行われます。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
refreshToken | String | 検査する Refresh Token |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
token | Object | 検査する Access Token |
token.refreshToken | String | getRefreshTokenに渡された Refresh Token |
token.refreshTokenExpiresAt | Date | 期限切れ時間 |
token.client | Object | |
token.client.id | String | Access Tokenに該当する Client ID |
Example Code
getAccessTokenのサンプルコードは、次の通りです。
{
getRefreshToken: token => {
if (!token || token === 'undefined') return false
return new Promise(resolve => {
// DBなどから渡された tokenの有効性(存在有無)を検査後にレスポンス
})
}
}
getClient
Authorization Codeで実装された getClientをそのまま使用できます。
getAuthorizationCode
saveAuthorizationCodeで保存された Authorization Codeを取得する役割をします。実装によっては、DBまたは In Memory Storageから取得できます。保存された AuthorizationCodeを Tokenの発行時に getAuthorizationCode Modelから取り出し、有効性を検証できます。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
authorizationCode | String | 照会する Authorization Code |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
code | Object | 照会された Code |
code.code | String | Authorization Code |
code.expiresAt | Date | 期限切れ時間 |
code.redirectUri | String | 発行された Authorization Codeに使用される Redirect URI |
code.client | Object | 発行された Authorization Codeの Client情報 |
code.client.id | String | 発行された Authorization Codeの Client ID情報 |
code.user | Object | 発行された Authorization Codeの User情報 |
saveToken
generateAccessToken/generateRefreshTokenで作成された Tokenを保存する役割をします。実装によっては、DBまたは In Memory Storageに保存できます。保存時に saveTokenでは Access Token/Refresh Tokenの両方を保存する必要があることにご注意ください。保存時は1つの Modelで、照会時はそれぞれの Modelで照会することになります。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
token | Object | 保存する Token |
token.accessToken | String | 保存する Access Token |
token.accessTokenExpiresAt | Date | Access Tokenの期限切れ時間 |
token.refreshToken | String | 保存する Refresh Token |
token.refreshTokenExpiresAt | Date | Refresh Tokenの期限切れ時間 |
client | Object | 発行された Tokenの Client情報 |
user | Object | 発行された Tokenの User情報 |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
token | Object | 保存した Token |
token.accessToken | String | 保存した Access Token |
token.accessTokenExpiresAt | Date | Access Tokenの期限切れ時間 |
token.refreshToken | String | 保存した Refresh Token |
token.refreshTokenExpiresAt | Date | Refresh Tokenの期限切れ時間 |
token.client | Object | 発行された Tokenの Client情報 |
token.client.id | String | 発行された Tokenの Client ID情報 |
token.user | Object | 発行された Tokenの User情報 |
トークン発行の統合 Example
authenticateのサンプルコードは、次の通りです。
const oauth = new OAuth2Server({model: ...}); // 先に実装された Model Objectを転送
// 下記の Handlerを PRISM OAuth2.0ガイドに従って/prism/v1/service/oauth2/token Routerで動作するように設定可能
function tokenHandler(options) { // optionsには Token Life Timeなどのオプションを追加可能(https://oauth2-server.readthedocs.io/en/latest/api/oauth2-server.html#token-request-response-options-callback)
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
return oauth.token(request, response, options) // oauth.authenticateを呼び出すことで先に実装した Modelsが内部的に呼び出され、authorization code/refresh token -> new tokenを発行
.then(function(code) {
res.locals.oauth = {token: token};
next();
})
.catch(function(err) {
// handle error condition
});
}
}
サンプルコードでは oauth.token(...)を包む Handlerを実装しましたが、上記サンプルコードの oauth.token(...)を API認証が必要な Routerなどで呼び出すことで、PRISM OAuth2.0連携のための/prism/v1/service/oauth2/token APIのレスポンスとして使用できます。
3. Authenticate(認証)
node-oauth2-serverでは発行された Access Tokenを利用した認証機能も提供します。認証機能のために実装する Modelは getAccessTokenです。
getAccessToken Model
ユーザーから渡された accessTokenが実際に存在する accessTokenかどうかを照会する目的で使用されます。DBなどで accessTokenを照会できます。
Arguments
因子の説明は次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
accessToken | String | 検査する Access Token |
[callback] | Function | Promiseで返さない場合に使える callback関数 |
Return Value
レスポンスボディの説明は、次の通りです。
フィールド | タイプ | 説明 |
---|---|---|
token | Object | 検査する Access Token |
token.accessToken | String | getAccessTokenに渡された Access Token |
token.accessTokenExpiresAt | Date | 期限切れ時間 |
token.client | Object | |
token.client.id | String | AccessTokenに該当する Client ID |
Example Code
getAccessTokenのサンプルコードは、次の通りです。
{
getAccessToken: token => {
if (!token || token === 'undefined') return false
return new Promise(resolve => {
// DBなどから渡された tokenの有効性(存在有無)を検査後にレスポンス
})
}
}
authenticateの例
authenticateのサンプルコードは、次の通りです。
const oauth = new OAuth2Server({model: ...}); // 先に実装された Model Objectを転送
function authenticateHandler(options) {
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
return oauth.authenticate(request, response, options) // oauth.authenticateを呼び出すことで実装していた getAccessTokenが内部的に呼び出され、Tokenを検証
.then(function(token) {
res.locals.oauth = {token: token};
next(); // Access Tokenが正常に認証され、次の MiddleWareに移行
})
.catch(function(err) {
// handle error condition
});
}
}
サンプルコードの oauth.authenticate(...)を API認証が必要な Routerなどで Middlewareとして登録することで、ビジネスロジックと分離して認証できます。