APIキー認証
必要な依存関係: io.ktor:ktor-server-auth, io.ktor:ktor-server-auth-api-key
APIキー認証は、クライアントがリクエストの一部(通常はヘッダー)として秘密鍵を渡す、シンプルな認証方法です。このキーは識別子と認証メカニズムの両方の役割を果たします。
Ktorでは、ルートを保護し、クライアントのリクエストを検証するためにAPIキー認証を使用できます。
Ktorにおける認証の全般的な情報は、Ktor Serverでの認証と認可セクションで確認できます。
APIキーは機密として扱い、安全に送信する必要があります。転送中のAPIキーを保護するために、HTTPS/TLSを使用することをお勧めします。
依存関係の追加
APIキー認証を有効にするには、ビルドスクリプトに ktor-server-auth と ktor-server-auth-api-key アーティファクトを追加します。
implementation("io.ktor:ktor-server-auth-api-key:$ktor_version")
implementation("io.ktor:ktor-server-auth:$ktor_version")implementation "io.ktor:ktor-server-auth-api-key:$ktor_version"
implementation "io.ktor:ktor-server-auth:$ktor_version"<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-server-auth-api-key-jvm</artifactId>
<version>${ktor_version}</version>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-server-auth</artifactId>
<version>${ktor_version}</version>
</dependency>APIキー認証のフロー
APIキー認証のフローは以下の通りです。
- クライアントが、サーバーアプリケーションの特定のルートに対して、ヘッダー(通常は
X-API-Key)にAPIキーを含めてリクエストを送信します。 - サーバーはカスタムの検証ロジックを使用してAPIキーを検証します。
- キーが有効な場合、サーバーはリクエストされたコンテンツを応答します。キーが無効または欠落している場合、サーバーは
401 Unauthorizedステータスを応答します。
APIキー認証のインストール
apiKey 認証プロバイダーをインストールするには、install(Authentication) ブロック内で apiKey 関数を呼び出します。
import io.ktor.server.application.*
import io.ktor.server.auth.*
// ...
install(Authentication) {
apiKey {
// APIキー認証を設定する
}
}オプションで、プロバイダー名を指定して、特定のルートを認証するために使用することもできます。
APIキー認証の設定
このセクションでは、apiKey 認証プロバイダーの具体的な設定について説明します。
Ktorでさまざまな認証プロバイダーを設定する方法については、認証の設定を参照してください。
ステップ 1: APIキープロバイダーの設定
apiKey 認証プロバイダーの設定は、ApiKeyAuthenticationProvider.Config クラスを通じて公開されます。以下の例では、次の設定が指定されています。
validate関数はリクエストから抽出されたAPIキーを受け取り、認証に成功した場合はPrincipalを返し、失敗した場合はnullを返します。
最小限の例を次に示します。
data class AppPrincipal(val key: String) : Principal
install(Authentication) {
apiKey {
validate { keyFromHeader ->
val expectedApiKey = "this-is-expected-key"
keyFromHeader
.takeIf { it == expectedApiKey }
?.let { AppPrincipal(it) }
}
}
}キーの場所のカスタマイズ
デフォルトでは、apiKey プロバイダーは X-API-Key ヘッダーからAPIキーを探します。
headerName を使用してカスタムヘッダーを指定できます。
apiKey("api-key-header") {
headerName = "X-Secret-Key"
validate { key ->
// ...
}
}ステップ 2: APIキーの検証
検証ロジックはアプリケーションの要件によって異なります。一般的なアプローチは以下の通りです。
静的なキーの比較
単純なケースでは、定義済みのキーと比較できます。
apiKey {
validate { keyFromHeader ->
val expectedApiKey = environment.config.property("api.key").getString()
keyFromHeader
.takeIf { it == expectedApiKey }
?.let { AppPrincipal(it) }
}
}機密性の高いAPIキーは、ソースコードではなく設定ファイルや環境変数に保存してください。
データベースでの検索
複数のAPIキーがある場合は、データベースに対して検証します。
apiKey {
validate { keyFromHeader ->
// データベースでキーを検索する
val user = database.findUserByApiKey(keyFromHeader)
user?.let { UserIdPrincipal(it.username) }
}
}複数の検証基準
複雑な検証ロジックを実装できます。
apiKey {
validate { keyFromHeader ->
val apiKey = database.findApiKey(keyFromHeader)
// キーが存在し、アクティブで、期限切れでないかを確認する
if (apiKey != null &&
apiKey.isActive &&
apiKey.expiresAt > Clock.System.now()
) {
UserIdPrincipal(apiKey.userId)
} else {
null
}
}
}ステップ 3: チャレンジの設定
challenge 関数を使用して、認証が失敗したときに送信されるレスポンスをカスタマイズできます。
apiKey {
validate { key ->
// 検証ロジック
}
challenge { defaultScheme, realm ->
call.respond(
HttpStatusCode.Unauthorized,
"Invalid or missing API key"
)
}
}ステップ 4: 特定のリソースの保護
apiKey プロバイダーを設定した後、authenticate 関数を使用してアプリケーション内の特定のリソースを保護できます。認証に成功した場合、ルートハンドラー内で call.principal 関数を使用して認証済みのプリンシパルを取得できます。
routing {
authenticate {
get("/") {
val principal = call.principal<AppPrincipal>()!!
call.respondText("Hello, authenticated client! Your key: ${principal.key}")
}
}
}APIキー認証の例
APIキー認証の完全な最小構成の例は以下の通りです。
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
data class AppPrincipal(val key: String) : Principal
fun Application.module() {
val expectedApiKey = "this-is-expected-key"
install(Authentication) {
apiKey {
validate { keyFromHeader ->
keyFromHeader
.takeIf { it == expectedApiKey }
?.let { AppPrincipal(it) }
}
}
}
routing {
authenticate {
get("/") {
val principal = call.principal<AppPrincipal>()!!
call.respondText("Key: ${principal.key}")
}
}
}
}ベストプラクティス
APIキー認証を実装する際は、以下のベストプラクティスを考慮してください。
- HTTPSを使用する: 傍受を防ぐため、APIキーは常にHTTPS経由で送信してください。
- 安全に保存する: APIキーをソースコードにハードコードしないでください。環境変数または安全な設定管理を使用してください。
- キーのローテーション: APIキーを定期的にローテーションするためのメカニズムを実装してください。
- レート制限: 悪用を防ぐために、APIキー認証をレート制限(Rate limiting)と組み合わせてください。
- ロギング: セキュリティ監視のために認証の失敗をログに記録しますが、実際のAPIキーは決してログに記録しないでください。
- キーの形式: APIキーには暗号学的に安全なランダム文字列(例:UUIDやBase64エンコードされたランダムバイト)を使用してください。
- 複数のキー: アプリケーションや目的ごとに、ユーザーあたり複数のAPIキーをサポートすることを検討してください。
- 有効期限: セキュリティを強化するために、キーの有効期限を実装してください。
