概要
Firebase StorageのgetSignedUrlメソッドによる署名付きURLを使用した際にハマった際の忘備録
背景
FirebaseのCloudFunctionsでAdmin SDKを使用すると、Firebase Storageのファイルに関して下記のような有効期限を指定した署名付きURLを発行して利用することができます。
(getSignedUrl 参考)
import * as admin from "firebase-admin";
//略
const bucket = admin.storage().bucket(buketName);
const [fileList] = await bucket.getFiles();
for (const file of fileList) {
const [url] = await file.getSignedUrl({
action: "read",
expires: "03-09-2491" // アクセス可能な有効期限
});
}
なお、CloudFunctionsで使用するAdminSDKではない、クライアント用のSDKには使用する場合には、getDownloadURLといったメソッドがありますが、AdminSDKの場合は上記署名付きURLによる取得処理になります。
(参考)
問題
上記で取得したURLをFirestoreに画像のダウンロードURLとして保存して、Webサイト上でそのURLを使用して画像を表示した場合に、一定期間を過ぎると画像が表示されなくなるといった問題が発生しました。
直接URLにブラウザからアクセスすると下記のようなエラーが表示されるようになり、画像の表示ができなくなっていることが分かります。
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
</Message>
<StringToSign>
GET 16447017600 xxxxxx/xxxx.jpg
</StringToSign>
</Error>
expiresで指定した期限より早く使用できなくなってしまう理由がわからず、色々と調べているとstackoverflow上でも似たような症状が発生しているスレッドが見つかりました。
(リンク)
詳細までは把握できていませんが、結局のところ、Google側で1週間単位で秘密鍵の変更を行っており、その関係で使用できなくなっているようです。公式のドキュメントのサンプルコード自体が2022年といった未来をしているので解せないところですが・・・。
確認はしていませんが、同じ仕組みを使用しているGCPでも同じ症状が起きるようです。
解決策
よく使用されているテクニックですが、最終的に署名付きURLをやめて、Storageのアクセス権限を変更し、下記のようなバケット名とファイルパスから固定URLを指定することでアクセスする方式に変更して対応しました。
(参考)
const url = `https://firebasestorage.googleapis.com/v0/b/${buketName}/o/${encodeURIComponent(filepath)}?alt=media`;