ログイン

トークンベースで認証の簡素化

トークン ベース認証と、アプリケーションにJWTを簡単に実装する方法について。

token-based-authentication-made-easy

トークンベースの認証

トークンは、それ自体では意味や用途を持たないデータですが、正しいトークン化システムと組み合わせると、アプリケーションを保護する上で重要な役割を果たします。トークンベースの認証の場合、サーバーへの各リクエストに署名付きトークンを確実に付け、サーバーがその信頼性を検証した時のみ、そのリクエストに応答します。

JSON Web Token (JWT) はオープン標準 ( RFC 7519 ) であり、JSONオブジェクトとしてエンコードされたパーティ間で情報を安全に送信するための、コンパクトで自己完結型の方法を定義します。JWTは、クエリ文字列、ヘッダー、およびPOSTリクエストの本文内でトークンを簡単に送信できる、コンパクトなサイズのため広く普及しています。

最新のJWTを今すぐ使用してみませんか?無料のガイドをダウンロードする

なぜトークンを使うのか?

トークンの使用には、Cookieなどの従来の方法と比較して多くの利点があります。

  • トークンはステートレスです。トークンは自己完結型で、認証に必要なすべての情報が含まれています。サーバーがセッション状態を保存する必要がなくなるため、スケーラビリティに優れています。
  • トークンはどこからでも生成できます。トークンの生成はトークンの検証から切り離されているため、トークンの署名を別のサーバーで処理したり、Auth0などの別の会社を介して処理したりすることもできます。
  • きめ細かいアクセス制御。トークンのペイロード内で、ユーザーの役割と権限、およびユーザーがアクセスできるリソースを簡単に指定できます。

これらは、JSON Web Token (JWT) が提供する利点のほんの一部です。詳細については、認証を管理するためのトークンとCookieを比較してより深く検討した、こちらのブログ投稿をご覧ください。

JSON Web Token (JWT) の構造

JSON Web Token (JWT) は、次の 3 つの部分から構成されます。ヘッダーペイロード、および署名。ヘッダーとペイロードはBase64でエンコードされ、ピリオドで連結され、最後に結果がアルゴリズムで署名され、ヘッダー.クレーム.署名の形式でトークンが生成されます。ヘッダーは、トークンのタイプと、トークンの署名に使用された、トークンの種類とハッシュアルゴリズムを含むメタデータで構成されています。ペイロードには、トークンがエンコードしているクレームデータが含まれています。最終的に次のようになります。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZXNzYWdlIjoiSldUIFJ1bGVzISIsImlhdCI6MTQ1OTQ0ODExOSwiZXhwIjoxNDU5NDU0NTE5fQ.-yIVBD5b73C75osbmwwshQNRC7frWUYrqaTjTpza2y4

トークンは操作から保護するため署名されています。暗号化されてはいません。つまり、トークンを簡単にデコードしてその内容を明らかにできるということです。jwt.ioに移動して上記のトークンを貼り付けると、ヘッダーとペイロードを読み取ることができますが、正しいシークレットがなければトークンは役に立たず、「無効な署名」というメッセージが表示されます。正しいシークレット (この例では文字列 L3@RNJWT ) を追加すると、「署名が検証されました」というメッセージが表示されます。

JWT.io を使用した WTのデコード

実際の状況では、クライアントがサーバーにリクエストを送信し、リクエストとともにトークンを渡します。サーバーはトークンの検証を試み、成功した場合はリクエストの処理を続行します。サーバーがトークンを検証できなかった場合、サーバーは401エラー を送信し、承認を検証できなかったため、要求を処理できなかったというメッセージを送信します。

JSON Web Token (JWT) のベストプラクティス

実際にJWTを実装する前に、トークンベースの認証がアプリケーションに適切に実装されていることを確認するための、いくつかのベストプラクティスについて説明しましょう。

  • 秘密を守って、安全を守る。署名キーは他の資格情報と同様に扱い、絶対に必要とするサービスにのみ開示します。
  • 機密データをペイロードに追加しないでください。トークンは操作から保護するために署名されており、簡単にデコードされます。最高のパフォーマンスとセキュリティを得るために、ペイロードに最小限の数のクレームを追加します。
  • トークンに有効期限を設定します。厳密には、いったんトークンが署名されると、署名キーが変更されるか、有効期限が明確に設定されない限り永久に有効です。これによって潜在的な問題起きる可能性があるため、トークンの有効期限の設定またはトークンの取り消し、あるいはその両方を行う戦略を立ててください。
  • HTTPSを採用します。HTTPS以外の接続でトークンを送信しないでください。そのような要求は傍受される可能性があり、トークンが危険にさらされます。
  • すべての承認のユースケースを検討してください。たとえば、トークンがサーバーから生成されたことを確認する、セカンダリトークン検証システムを追加することは一般的ではありませんが、要件を満たすために必要な場合があります。

詳細とベストプラクティスについては、「トークンについて知っておくべき10項目」のブログ投稿をご覧ください。

トークンベースで認証の簡素化

トークンベースの認証とJWTは広くサポートされています。JavaScript、Python、C#、Java、PHP、Ruby、Goなどには、JSON web token (JWT) に簡単に署名して検証するためのライブラリがあります。API を実装して、JWTでどれだけ迅速に保護できるか見てみましょう。

当社がNode.js を使用してAPIを構築することを選択したのは、セットアップが最小限で済むためです。JWTの実装のコードを見てみましょう。

// 依存関係を読み込む
var express = require('express');
var jwt = require('jsonwebtoken');

var app = express();

// ウェルカムメッセージを表示するホームルートを登録する
// このルートはトークンなしでアクセスできます
app.get('/', function(req, res){
  res.send('Welcome to our API');
})

// ルートを登録して新しいトークンを取得する
// 実際の状況では、ユーザー資格情報を認証します
// トークンを作成する前ですが、簡単にするためにこのルートにアクセスします
// 2分間有効な新しいトークンを生成します
app.get('/token', function(req, res){
  var token = jwt.sign({username:'ado'}, 'supersecret',{expiresIn:120});
  res.send(token)
})

// データを表示するために有効なトークンを必要とするルートを登録する
app.get('/api', function(req, res){
  var token = req.query.token;
  jwt.verify(token, 'supersecret', function(err, decoded){
    if(!err){
      var secrets = {'accountNumber' : '938291239','pin' : '11289','account' : 'Finance'};
      res.json(secrets);
    } else {
      res.send(err);
    }
  })
})

// ポート3000でアプリを起動します
app.listen('3000');

現在のAPIをテストするために、アプリケーションを実行して localhost:3000 に移動しましょう。「APIへようこそ」というメッセージだけが表示されます。 次に、localhost:3000/apiルートに移動すると、トークンを取得できなかったことを示すJWTエラー メッセージが表示されます。localhost:3000/token ルートに移動すると、新しいトークンが生成されていることがわかります。このトークンをコピーし、localhost:3000/api?token={ADD-COPIED-TOKEN-HERE} に移動すると、会社の金融口座が表示されます。これは意図した応答です。

ほんの数行のコードで、APIエンドポイントを保護することができました。トークンを生成する前の適切なユーザー認証の処理については触れませんでした。それはこれから、Auth0を使って行います。

Auth0によるJWT認証

Auth0を使用した認証フローを示すために、コードに若干の変更を加える必要があります。変更された点をみてみましょう。

// 依存関係を読み込む
var express = require('express');
var jwt = require('express-jwt');

var jwtCheck = jwt({
  secret: new Buffer('{YOUR-APP-SECRET}', 'base64'),
  audience: '{YOUR-APP-CLIENT-ID}'
});

var app = express();

// コントローラー内でトークンをチェックするのではなく
// ミドルウェアを使用するので、トークンが無効な場合は
// リクエストをさらに実行することを停止します
app.use('/api', jwtCheck);

app.get('/', function(req, res){
  res.send('Welcome to our API');
})

app.get('/api', function(req, res){
  var secrets = {'accountNumber' : '938291239','pin' : '11289','account' : 'Finance'};
  res.json(secrets);
})

app.listen('3000');

これが機能することをテストするために、サーバーを起動して localhost:3000/api に移動しましょう。認証トークンが送信されていないというメッセージが表示されます。Auth0プレイグラウンドに進み、資格情報を追加してトークンを取得しましょう。次のコードをプレイグラウンドに追加します。

var domain = '{YOUR-AUTH0-DOMAIN}.auth0.com';
var clientID = '{YOUR-APP-CLIENT-ID}';

var lock = new Auth0Lock(clientID, domain);
lock.show({
  focusInput: false,
  popup: true,
}, function (err, profile, token) {
  alert(token)
});

トークンを確実に取得するには、Auth0ダッシュボードのアプリ設定に移動し、https://auth0.github.io/playground を、許可されたコールバックURLのリストに 追加する必要があります。Auth0プレイグラウンドにログインするか、またはアカウントを作成しみましょう。トークンを示すポップアップが表示されます。

トークンの内容を確認するには、 jwt.io でデコードします。トークンを検証するには、Auth0アプリのクライアントシークレットが必要で、シークレットbase64エンコードのボックスにチェック印を入れる必要があります。これを行うと、「署名が検証されました」というメッセージが表示されるはずです。

当社のAPIがこのトークンで作動することをテストするには、localhost:3000/api に対して GET 要求を行い、Authorizationヘッダーでトークンを送信する必要があります。これを行う最も簡単な方法は、APIエンドポイントのテストを簡素化する Postmanなどのアプリを使用することです。呼び出しを行うときに 認証ヘッダーを追加し、値にBearer {TOKEN}を追加します。呼び出しが行われると、jwtCheckミドルウェアがリクエストを調べ、認証ヘッダーが正しい形式であることを確認し、トークンを抽出して検証し、検証された場合は残りのリクエストを処理します。JWT の機能を紹介するためにデフォルト設定のみを使用しましたが、ドキュメントでさらに多くのことを学ぶことができます。

トークンベースの認証のユースケース

JWT認証を実装してAPIを保護することが、いかに簡単かをご紹介しました。最後に、トークンベースの認証が最も適しているユースケースを見てみましょう。

  • Platform-as-a-Service (PaaS) アプリケーション – さまざまなフレームワークやクライアントによって使用されている、RESTful APIを公開します。
  • モバイルアプリ – サービスとやり取りをする、ネイティブまたはハイブリッドモバイル アプリを実装します。
  • シングルページアプリケーション (SPA) – Angular や Reactなどのフレームワークを使用して、最新のアプリケーションを構築します。

JSON Web Token (JWT) 使用については、こちらの投稿で、さらに多くのリソースをご覧ください。

登録無料

今すぐ構築を開始し、Auth0 ID プラットフォームでお使いのアプリを保護しましょう。

3D login box