GoogleフォトとS3を繋ぐ Photos Picker App
はじめに
Google フォトから選んだ写真を S3 にアップロードする Web アプリ(Photo Picker)を作りました。当初は「Google フォトの任意の写真を自動取得してS3にアップロードすること」を狙っていましたが、Google Photos API の仕様変更により、APIによる写真取得には基本的にユーザーの UI 操作が必要になりました。本アプリでは Google Photos Picker API と Google Identity Services (GIS) をフロントエンドから利用し、ユーザーが選んだ写真を安全に S3 へ転送するところまでをWebアプリで実現しています。
私はこのアプリ経由でアップロードした画像を電子ペーパーが取得/描写し、デジタルアートフレームとして利用しています。そちらについては別の記事 AWS × e-Paperで作るデジタルアートフレームで紹介しています。
つくったもの
- Google アカウントでブラウザからサインインし、Google Photos Picker UI でGoogleフォトの写真を選択
- 選択した写真をブラウザが直接 S3 に PUT(presigned URL を Lambda が発行)
- ローカルファイルのドラッグイン/選択にも対応し、同じフローでアップロード
- ブラウザでアップロード済み画像の表示と削除の機能

システム全体像
Webアプリは CloudFront + S3 による静的ホスティングで動作します。
アプリのユーザ認証やアップロード済み画像の表示/削除はそれぞれ API Gateway + Lambdaで構成しています。
CloudFront + S3: Web アプリを配信
静的 Web アプリ (HTML/JS/CSS) をホスティング。S3 バケットは Public Access Block + CloudFront Origin Access Control (OAC) で保護しています。

API Gateway + Lambda + S3: 画像のアップロード/管理
-
API Gateway + Lambda
- API Gateway
/presign→ Lambdapresign: S3 へのアップロード URL を発行 - API Gateway
/uploads→ Lambdamanage_uploads: アップロード済み一覧の取得・削除
※ LambdaにてGoogle ID トークンの認証を行う。事前に許可したGoogleアカウントのみリクエストを許可
- API Gateway
-
S3 バケット
- S3
uploads/: オリジナル画像の保管先
- S3

記事で扱うコード
picker2paper/
├─ cdk_photo_picker/ # 本記事で扱う Web + API
│ ├─ app.py # CDK エントリーポイント
│ ├─ photo_picker/app_stack.py
│ ├─ lambda/
│ │ ├─ presign/handler.py
│ │ └─ manage_uploads/handler.py
│ └─ site/
│ ├─ index.html
│ ├─ main.js
│ └─ config.js
├─ cdk_display_pipeline/ # e‑Paper 配信(別記事で解説)
└─ raspberryPi_code/ # デバイス側スクリプト(別記事で解説)
補足:
cdk_display_pipeline/,raspberryPi_code/は e-Paper を使って写真フレームを構築したい方向けのコードです。詳細は別の記事 AWS × e-Paperで作るサーバレス写真フレームを参照してください。
Web アプリ本体は picker2paper/cdk_photo_picker/site/ 以下にあります。config.js には API エンドポイントと Google OAuth クライアント ID を記述してからデプロイしてください。(詳細は後述)
Google Cloud 設定
Google Photos Picker API を利用するにあたり、Google Cloudにて APIの有効化と、OAuth クライアントの作成を行います。大まかには公式のマニュアルに従って作業を進めます。
- Google Cloud コンソールで新規プロジェクトを作成
-
APIの有効化
- [API とサービス] > [ライブラリ] から
Google Photos Picker APIを有効化
- [API とサービス] > [ライブラリ] から
-
OAuth 2.0 クライアント ID 作成
- [API とサービス] > [認証情報] から認証情報 (OAuth クライアントID) を作成
- アプリケーションの種類は
ウェブ アプリケーション - 「承認済みの JavaScript 生成元」と「承認済みのリダイレクト URI」にはどちらもWebアプリの公開URL(例:
https://photopicker.example.com) を登録 - 作成時に表示されるクライアントID, クライアントシークレットを保管 (クライアントIDを後ほど利用します。)
-
OAuth 同意画面の設定
- [API とサービス] > [OAuth 同意画面] > [データアクセス] から「スコープを追加または削除」で
https://www.googleapis.com/auth/photospicker.mediaitems.readonlyを追加 - [API とサービス] > [OAuth 同意画面] > [対象] からテストユーザーを追加
- Googleフォトの写真をアップロードさせたい Google アカウントを追加
- [API とサービス] > [OAuth 同意画面] > [データアクセス] から「スコープを追加または削除」で
-
クライアント ID の共有
発行したクライアント ID をsite/config.jsと CDK コンテキスト (googleClientId) に設定します。
AWS 環境の構築
事前準備
(任意) Amazon Route 53 の DNS ゾーン
以降の証明書発効時のドメイン認証や、Webアプリを自身のドメインで公開する際にDNSゾーンが必要です。
Route 53利用の場合は$0.5/月かかります。その他のDNSサービスでも代替可能です。
AWS ACMによるサーバ証明書の作成
Webアプリの公開ドメイン(例: photopicker.example.com) 用の証明書を発行します。
サーバ証明書はCloudFrontから提示するため、us‑east‑1 リージョンで発行します。
CDK スタックの準備
picker2paper/cdk_photo_picker/
├─ app.py
├─ cdk.json
├─ requirements.txt
├─ photo_picker/app_stack.py
└─ lambda/
├─ presign/
└─ manage_uploads/
デプロイ
cd picker2paper/cdk_photo_picker
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cdk bootstrap # 初回のみ
cdk deploy PhotoPickerAppStack \
--context domainName=photopicker.example.com \
--context hostedZoneName=example.com \
--context manageDns=true \
--context siteBucketName=photopickerapp-site-ap-northeast-1-example \
--context uploadsBucketName=photopickerapp-uploads-ap-northeast-1-example \
--context uploadsPrefix=uploads/ \
--context processedPrefix=processed/ \
--context googleClientId=YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com \
--context allowedEmailDomains="example.com" \
--context allowedEmails="user1@example.com, user2@example.com" \
--context cloudFrontCertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
デプロイ後に確認する Outputs
-
SiteBucketName,UploadsBucketName: 作成された S3 バケット名 -
DistributionDomainName: CloudFront の自動割り当てドメイン -
PresignEndpointForConfig,ManageEndpointForConfig:site/config.jsに設定する API エンドポイント -
SiteDnsRecord:manageDns=falseの場合に出力される CloudFront エイリアス作成手順
Web アプリの設定(site/config.js)
Google Cloudで作成したクライアント ID と cdk deploy時のOutputs に応じて config.jsを以下のように設定します。
設定後、このconfig.jsを反映するために再度 cdk deployを実行します。
window.AppConfig = {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com",
scopes: [
"https://www.googleapis.com/auth/photospicker.mediaitems.readonly"
],
},
upload: {
presignEndpoint: "https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/prod/presign",
manageEndpoint: "https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/prod/uploads",
s3KeyPrefix: "uploads/"
}
};
使い方
- Web にアクセスし、「Google にサインイン」をクリック
- 「写真を選択」を押して Google Photos Picker で写真を選ぶ
- 「選んだ写真を S3 へアップロード」を押してアップロード
- 下部の一覧からアップロード済みファイルを確認(必要なら削除)

(補足) セキュリティとアクセス制御
- Webアプリへのアクセス時にGoogleのログイン認証を求められます
- Googleフォト連携(Google Photos Picker API)の利用は、Google Cloud設定にてテストユーザとして追加したアカウントのみに限定されます
- API Gateway
presign/uploadsによる画像のアップロード/参照は GoogleアカウントのID トークンを検証した上で実行します-
allowedEmailsに登録されたアカウント以外のリクエストは拒否します
-
まとめ
Google Photos Picker API とサーバーレス構成を組み合わせることで、ユーザー主導の写真選択フローを維持しつつ、安全に S3 へアップロードする仕組みを構築しました。フロントエンドは完全に静的なまま、Google 認証の検証や S3 署名付き URL の発行を Lambda に任せられるため、インフラ構成もシンプルにできました。
Discussion