IIIF Auth APIの必要性
IIIFは画像の相互運用性を重視するフレームワークですが、すべての画像が無制限に公開できるわけではありません。著作権の保護、利用規約への同意、館内限定公開、有償コンテンツなど、さまざまな理由で画像へのアクセスを制限する必要があるケースは数多く存在します。
たとえば、以下のようなシナリオが考えられます。
- 著作権保護: 著作権が存続する作品の高解像度画像を、登録ユーザーにのみ提供したい
- 段階的アクセス: 未認証ユーザーにはグレースケールや低解像度の画像を表示し、認証後にフルカラー・高解像度画像を提供したい
- 館内限定: 図書館や美術館の施設内からのアクセスのみ許可したい
- 利用規約への同意: 画像を表示する前に利用規約への同意を求めたい
IIIF Authentication APIは、これらの要件をIIIFビューアとイメージサーバーの間で標準的に処理するための仕様です。ビューアが認証の必要性を検知し、ユーザーに適切な認証手段を提示し、認証済みの状態で画像を取得する一連のフローを定義しています。
Auth API 1.0の概要
IIIF Auth API 1.0は、画像のinfo.jsonにサービス記述を追加する形で認証要件を表現します。認証のパターンとして以下の4つのインタラクションパターンが定義されています。
Login(ログイン)
最も一般的なパターンです。ユーザーにIDとパスワードの入力を求めます。ビューアは認証が必要であることを検知すると、ユーザーにログインを促すUIを表示します。ログインが完了すると、セッションCookieが設定され、以降のリクエストではフルアクセスが許可されます。
Clickthrough(クリックスルー)
利用規約への同意を求めるパターンです。ログイン情報は不要で、ユーザーが「同意する」ボタンをクリックするだけでアクセスが許可されます。規約を表示した上で明示的な同意を取得する仕組みとして利用されます。
Kiosk(キオスク)
施設内のIPアドレス範囲や特定のネットワークからのアクセスのみ許可するパターンです。ユーザーによる操作は不要で、サーバー側でアクセス元を判定して自動的に認証を行います。図書館内の端末でのみ高解像度画像を閲覧可能にするといった用途に適しています。
External(外部認証)
CAS、Shibbolethなどの外部認証システムと連携するパターンです。機関が既に運用している認証基盤を利用して、IIIFリソースへのアクセス制御を行います。
info.jsonでの記述
Auth API 1.0では、info.jsonのserviceプロパティに認証サービスの情報を記述します。
{
"@context": "http://iiif.io/api/image/2/context.json",
"@id": "http://example.org/image/sample.jpg",
"service": {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "http://example.org/auth/cookie/login/sample.jpg",
"profile": "http://iiif.io/api/auth/1/login",
"label": "ログインしてください",
"header": "認証が必要です",
"description": "フルカラー画像を閲覧するにはログインが必要です。",
"confirmLabel": "ログイン",
"service": [
{
"@id": "http://example.org/auth/token/login/sample.jpg",
"profile": "http://iiif.io/api/auth/1/token"
},
{
"@id": "http://example.org/auth/logout/login/sample.jpg",
"label": "ログアウト",
"profile": "http://iiif.io/api/auth/1/logout"
}
]
}
}
ビューアはこの情報を読み取り、labelやdescriptionをユーザーに表示し、confirmLabelのボタンで認証フローを開始します。認証が成功すると、Tokenサービスからアクセストークンを取得し、以降の画像リクエストに使用します。
Auth API 2.0の新機能と実装
Auth API 2.0は、1.0の経験を踏まえた大幅な刷新です。主な変更点と新しいアーキテクチャを解説します。
Probe Serviceの導入
Auth API 2.0で最も重要な変更は、Probe Service(AuthProbeService2)の導入です。1.0ではinfo.jsonの取得時に直接認証状態が評価されていましたが、2.0ではProbe Serviceを介して認証状態を確認する間接的な仕組みに変更されました。
この設計変更により、認証状態の確認と画像の配信が分離され、より柔軟なアクセス制御が可能になりました。
認証フローの全体像
Auth API 2.0の認証フローは以下のステップで進行します。
Step 1: 初回リクエスト
クライアントがinfo.jsonにアクセスします。未認証の場合、サーバーは401レスポンスとともにProbe ServiceのURLを返します。
{
"error": "Authentication required",
"service": [{
"@context": "http://iiif.io/api/auth/2/context.json",
"id": "http://example.org/api/iiif/probe",
"type": "AuthProbeService2"
}]
}
Step 2: Probe Serviceへの問い合わせ
クライアントはProbe Serviceに対してリクエストを送り、認証状態を確認します。未認証の場合、Probe Serviceは認証に必要なAccess ServiceとToken Serviceの情報を含むレスポンスを返します。
{
"@context": "http://iiif.io/api/auth/2/context.json",
"type": "AuthProbeResult2",
"status": 401,
"service": [{
"id": "http://example.org/api/iiif/access",
"type": "AuthAccessService2",
"profile": "active",
"label": "Login to IIIF Auth Demo",
"service": [{
"id": "http://example.org/api/iiif/token",
"type": "AuthAccessTokenService2"
}]
}]
}
Step 3: 認証ウィンドウの起動
クライアントはAuthAccessTokenService2のURLにmessageIdとoriginパラメータを付与して、ポップアップウィンドウで開きます。Token Serviceはログインページにリダイレクトし、ユーザーが認証情報を入力します。
Step 4: トークンの取得と伝達
ログインが成功すると、サーバーはJWT(JSON Web Token)を生成します。このトークンはwindow.postMessage()を使ってポップアップウィンドウから元のウィンドウに安全に伝達されます。
Step 5: 認証済みリクエスト
トークンを取得したクライアントは、AuthorizationヘッダーにBearerトークンを付与して再度info.jsonをリクエストします。サーバーはトークンを検証し、認証済みのユーザーに対して完全な画像情報を返します。
セキュリティ上の考慮事項
Auth API 2.0の実装では、以下のセキュリティ対策が重要です。
- JWTの署名検証: トークンの改ざんを防止するため、HS256やRS256アルゴリズムによる署名と検証を行う
- トークンの有効期限: JWTには適切な有効期限(exp)を設定し、期限切れトークンを拒否する
- CORS設定: IIIF画像はクロスオリジンで利用されることが多いため、適切なCORSヘッダーの設定が不可欠
- Origin検証: postMessageの受信時にOriginを検証し、不正なオリジンからのメッセージを拒否する
- HTTPS: 本番環境では必ずHTTPSを使用し、トークンの漏洩を防止する
Cantaloupeでのアクセス制御設定
Cantaloupe(IIIFイメージサーバー)は、Rubyスクリプトベースのdelegateメカニズムによって柔軟なアクセス制御を実装できます。
All or Nothing Access
最もシンプルなパターンは、正しいBearerトークンを持つリクエストのみを許可し、それ以外を拒否する方法です。
def authorize(options = {})
header = context['request_headers']
.select { |name, value| name.downcase == 'authorization' }
.values.first
if header&.start_with?('Bearer ')
token = header[7..header.length - 1]
return true if token == "test"
end
return {
'status_code' => 401,
'challenge' => 'Bearer charset="UTF-8"'
}
end
このスクリプトでは、AuthorizationヘッダーにBearer testが含まれていればアクセスを許可し、それ以外は401を返します。実際の運用では、トークンをデータベースや外部認証サービスで検証する実装に置き換えます。
段階的アクセス(Degraded Access)
未認証ユーザーに対して品質を落とした画像(グレースケールなど)を提供し、認証後にフルカラー画像を提供するパターンも実装できます。
def authorize(options = {})
header = context['request_headers']
.find { |name, value| name.downcase == 'authorization' }&.last
request_uri = context['request_uri']
filename, extension = extract_filename_and_extension(request_uri)
# グレースケール版は常にアクセス可能
return true if filename == "gray"
# 認証済みの場合はオリジナル画像にアクセス可能
if header&.start_with?('Bearer ')
token = header[7..-1]
return true if token == "test"
end
# 未認証の場合はグレースケール版にリダイレクト
{
'status_code' => 302,
'location' => "#{request_uri.sub(filename + extension, "gray#{extension}")}"
}
end
この仕組みでは、認証されていないリクエストに対して302リダイレクトでグレースケール画像のURLに転送します。ビューアのUIでは「ログインするとカラー画像を閲覧できます」というメッセージとともにログインボタンが表示され、ユーザーは認証の必要性と利点を理解した上で判断できます。
実装パターンと事例
テスト環境の構築
IIIF Auth APIの動作を確認するための環境として、digirati社が提供するiiif-auth-serverが利用できます。
git clone https://github.com/digirati-co-uk/iiif-auth-server
cd iiif-auth-server
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
export FLASK_APP=iiifauth
flask initdb
flask run
このサーバーは、Login、Clickthrough、Kiosk、Externalの各パターンのデモを提供します。Mirador 3と組み合わせて、各パターンの認証フローを実際に体験できます。
Auth API 2.0のデモ実装
Next.jsを使ったAuth API 2.0のデモ実装も公開されています。JWTベースのトークン管理、Probe Service、Access Serviceの各エンドポイントが実装されており、認証フローの全体を確認できます。localStorageによるトークンの永続化やstorageイベントを使ったタブ間同期など、実用的な実装パターンも含まれています。
国内の導入状況
日本国内では、IIIF Auth APIの導入はまだ限定的ですが、島根大学附属図書館などで実装事例が報告されています。著作権が存続する資料やプライバシーに配慮が必要な資料を扱う機関を中心に、今後の導入拡大が期待されます。
段階的なアクセス制限の設計
実際にIIIF Auth APIを導入する際は、アクセス制限の粒度と段階を慎重に設計する必要があります。
設計のポイント
コンテンツの分類: まず、所蔵資料を権利状態に基づいて分類します。パブリックドメインの資料、著作権が存続する資料、プライバシー配慮が必要な資料など、カテゴリごとにアクセスポリシーを定義します。
段階的な提供: 完全に非公開にするのではなく、段階的なアクセスを検討します。たとえば以下のような3段階が考えられます。
- オープンアクセス: メタデータと低解像度サムネイルを誰でも閲覧可能
- 制限付きアクセス: 利用規約に同意したユーザーに中解像度画像を提供
- フルアクセス: 登録ユーザーに高解像度画像とダウンロードを許可
ビューアの対応状況: Auth APIに対応したビューアは限られています。Mirador 3はAuth API 1.0に対応していますが、2.0への対応は発展途上です。導入にあたっては、利用予定のビューアの対応状況を確認し、必要に応じて独自のビューアを構築することも検討します。
ユーザー体験の配慮: 認証が必要な場合でも、ユーザーに対して適切なメッセージを表示し、なぜ認証が必要なのか、認証後にどのようなコンテンツにアクセスできるのかを明確に伝えることが重要です。failureHeaderやfailureDescriptionを使って、認証に失敗した場合の案内(問い合わせ先やアクセスポリシーへのリンクなど)も提供します。
IIIF Auth APIは、オープンアクセスの推進と権利保護のバランスを実現するための重要な仕様です。すべての資料を無制限に公開することが難しい現実に対して、標準化された方法でアクセス制御を実現し、利用者にとっても一貫した体験を提供できる点に大きな価値があります。