PHPでfirebase/php-jwtを使ってJWT認証を実装する

公開日: 


JWTとは

JSON Web Token(JWT)は、Webサービス間で安全に情報をやり取りするための仕組みです。

データはJSON形式で表現され、ヘッダー、クレーム、署名というカテゴリで構成されます。
中身は暗号化されることで、安全に情報を送受信できます。

クレームは、JSON Web Signature(JWS)やJSON Web Encryption(JWE)のペイロードに含まれており、Base64でエンコードされたJSON文字列として表現されます。

JWT認証

JWTは一度発行されると、取り消しが効かないことにより、

APIなどを使った、認証の場面において使われることが多いです。

ほかでもいろんなサンプルはたくあんありますが、読みにくいことが多く困ったので、

ここではライブラリを使ったシンプルな実装例のメモです。

ライブラリは firebase/php-jwt と acodercat/php-jwk-to-pem を使います。

<?php

// JWT認証

require_once(./autoload.php);

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use CoderCat\JWKToPEM\JWKConverter;

print(auth());  // デバッグ用

function auth() {

  // リクエストヘッダ取得
  $headers = getallheaders();
  $jwt = '';
  foreach ($headers as $name => $value) {
    if ($name == 'Authorization') {
      $jwt = $value;
      break;
    }
  }
  
  if ($jwt) {
    $url = 'https://...';  // 指定の公開鍵
    
    // kidを見つける
    $tks = explode('.', $jwt);
    if (count($tks) != 3) {
      // フォーマット不良
      return false;
    }
    list($headb64, $bodyb64, $cryptob64) = $tks;
    
    $jwtHeader = json_decode(JWT::urlsafeB64Decode($headb64), true);
    if (empty($jwtHeader['kid'])) {
      // kidがない
      return false;
    }
    
    // jwkから公開鍵取得
    $publicKey = '';
    $jwks = file_get_contents($url);
    $jwkData = json_decode($jwks, true);
    foreach ($jwkData['keys'] as $jwk) {
      if ($jwk['kid'] == $jwtHeader['kid']) {
        $jwkConverter = new JWKConverter();
        $publicKey = $jwkConverter->toPEM($jwk);
        break;
      }
    }
    if (!$publicKey) {
      // 取得失敗
      return false;
    }
    
    // 検証
    $decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
    
    if (!decoded) {
      // 検証失敗
      return false;
    }
    
    // 認証OK
    return true;
  }
  else {
    // 取得失敗
    return false;
  }

}

?>