今回はReact x Amplifyでアプリをデプロイし、Google認証を実装する手順についてまとめていきます。
Viteを使ってReactプロジェクトを作ります。
npm create vite@latest my-react-app -- --template react-ts
起動確認をします。
cd my-react-app
npm install
npm run dev
アクセスしてロゴが表示されていることを確認します。
必要なパッケージをインストールします。
npm install --save-dev @aws-amplify/backend@latest @aws-amplify/backend-cli@latest
続いてProjectのrootディレクトリにbackend amplifyプロジェクトを立ち上げます。
npm create amplify@latest
>>>
> my-react-app@0.0.0 npx
> create-amplify
? Where should we create your project? .
Installing devDependencies:
- @aws-amplify/backend
- @aws-amplify/backend-cli
- aws-cdk@^2
- aws-cdk-lib@^2
- constructs@^10.0.0
- typescript@^5.0.0
- tsx
- esbuild
Installing dependencies:
- aws-amplify
⠧ Installing devDependencies
このコマンドにより新たにディレクトリができあがります。
├── amplify/
│ ├── auth/
│ │ └── resource.ts
│ ├── data/
│ │ └── resource.ts
│ ├── backend.ts
│ └── package.json
理屈はあまり分かっていないのですが、デプロイ時にCloudformationと連携してawsのバックエンドリソースを立ち上げるのに用いられていそうです。auth
ディレクトリはCognitoのリソース作成に、data
ディレクトリはDynamoDBを用いる場合に記述をしていくディレクトリみたいです。
今回は認証だけ行いたいので、data
ディレクトリは 使いません。削除しましょう。
├── amplify/
│ ├── auth/
│ │ └── resource.ts
│ ├── backend.ts
│ └── package.json
このようになりました。
まずはemailとパスワードを利用した通常ログインを実装してみましょう。
今回は非常に簡単にCognitoと連携が行える@aws-amplify/ui-react
を利用します。
npm install @aws-amplify/ui-react
amplify/backend.ts
を編集します。といっても削除したdataの記述を消すだけです。以下のようにしましょう。
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
/**
* @see https://docs.amplify.aws/react/build-a-backend/ to add storage, functions, and more
*/
defineBackend({
auth,
});
続いて、記述した内容をsandbox環境に反映させます。
npx ampx sandbox
>>>
[Sandbox] Watching for file changes...
File written: amplify_outputs.json
以上のようにメッセージが出ましたら、Ctr + Cで終了させましょう。
amplify_outputs.jsonが生成されます。
{
"auth": {
"user_pool_id": "ap-northeast-1_poolid",
"aws_region": "ap-northeast-1",
"user_pool_client_id": "cognito_client_id",
"identity_pool_id": "ap-northeast-1:identity_pool_id",
"mfa_methods": [],
"standard_required_attributes": [
"email"
],
"username_attributes": [
"email"
],
"user_verification_types": [
"email"
],
"mfa_configuration": "NONE",
"password_policy": {
"min_length": 8,
"require_lowercase": true,
"require_numbers": true,
"require_symbols": true,
"require_uppercase": true
},
"unauthenticated_identities_enabled": true
},
"version": "1.2"
}
AWSマネジメントコンソールに行くと、Cognitoのユーザープールが作成されているかと思います。
続いてメインのコードを修正していきましょう。まずはsrc/main.tsx
でAmplifyを有効化してReactアプリを開始します。
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import '@aws-amplify/ui-react/styles.css'
import { Amplify } from 'aws-amplify'
import outputs from '../amplify_outputs.json'
Amplify.configure(outputs)
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
続いてsrc/app.tsxを以下のようにします。
import './App.css'
import { Authenticator } from '@aws-amplify/ui-react'
function App() {
return (
<Authenticator>
{({ signOut, user }) => (
<>
<div>
<h1>{user?.username}!</h1>
<p>認証されました</p>
<button
onClick={signOut}
>
Sign Out
</button>
</div>
</>
)}
</Authenticator>
)
}
export default App
npm run devすると、以下のようなログイン画面が立ち上がります。
Create Accountしてみましょう。
メールでコードが届くので、入力してサインアップします。
Cognitoにユーザー登録がされ、認証が行われたことが分かります。
続いてGoogle側の設定をしていきましょう。
基本的にはAmplifyの公式手順に沿って行っていきます。
https://docs.amplify.aws/react/build-a-backend/auth/concepts/external-identity-providers/
まずはGoogle developer console.にアクセスをします。
プロジェクトの選択からプロジェクトを作成をします。
次の画面で適当にMy Amplify Project
のようなプロジェクトを登録します。
左ペインの認証情報から認証情報を作成をクリックします。OAuth クライアント ID を選択します。
続いての画面で「OAuth クライアント ID を作成するには、まず同意画面で設定を行う必要があります」と出てくるので同意画面に遷移します。
日本語が怪しい気がしますが、気にせずにつづけます。
外部を選択します。
続いての画面でアプリ名を聞かれますので、適当に入力します。
メールアドレスは自分のアドレスを入れましょう。
他必須じゃないところは空欄でいいです。
進めるとテストユーザーを追加するボタンが出現するので、自分のメールアドレスを指定します。
追加したらOAuth クライアント IDの作成に戻ります。
承認済みの JavaScript 生成元と承認済みのリダイレクト URIは本来はCognitoのDomainに即したURLを入れますが、現時点ではCognitoのDomainは生成されていないので、一旦はhttps://www.example.comのような適当な値を入れて作成します。
クライアントIDとクライアントSECRETが発行されるので、メモしておきましょう。
続いてCognitoをGoogleでログインできるように更新しておきます。
amplify/auth/resource.tsを以下のようにします。
import { defineAuth, secret } from '@aws-amplify/backend';
/**
* Define and configure your auth resource
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
*/
export const auth = defineAuth({
loginWith: {
email: true,
externalProviders: {
google: {
clientId: secret('GOOGLE_CLIENT_ID'),
clientSecret: secret('GOOGLE_CLIENT_SECRET'),
scopes: ['email']
},
callbackUrls: [
'http://localhost:5173/',
],
logoutUrls: ['http://localhost:5173/'],
}
},
});
次に先ほどメモしたGOOGLE_CLIENT_IDとGOOGLE_CLIENT_SECRETを環境変数に反映させます。
npx ampx sandbox secret set GOOGLE_CLIENT_ID
npx ampx sandbox secret set GOOGLE_CLIENT_SECRET
再びSandbox環境に反映をさせます。
npx ampx sandbox
AWSマネジメントコンソールからCognitoに行きますとドメインが発行されています。
再びGoogleに戻ってドメインに即したURLを入力します。
承認済みの JavaScript 生成元:https://your-domain.auth.ap-northeast-1.amazoncognito.com
承認済みのリダイレクト URI:https://your-domain.auth.ap-northeast-1.amazoncognito.com/oauth2/idpresponse
続いてsrc/App.tsx
のSocial Providerにgoogleを指定します。
import './App.css'
import { Authenticator } from '@aws-amplify/ui-react'
function App() {
return (
<Authenticator socialProviders={['google']}>
{({ signOut, user }) => (
<>
<div>
<h1>{user?.username}!</h1>
<p>認証されました</p>
<button
onClick={signOut}
>
Sign Out
</button>
</div>
</>
)}
</Authenticator>
)
}
export default App
npm run devして立ち上げると、よくあるGoogleログインリンクが表示され、ユーザーの作成、ログインが行えるはずです。
続いて本番へのデプロイを行っていきましょう。
まずはgithubにソースコードをpushします。Privateで構いません。
続いてAmplifyにアクセスしてGithubベースでアプリを作成します。
先ほどpushしたリポジトリを指定します。
そのまま、デフォルトの設定のままデプロイをします。
デプロイが始まります。
一定時間が経過するとデプロイが失敗します。
2024-10-14T11:03:33.044Z [INFO]: SecretNotSetError: The secret 'GOOGLE_CLIENT_ID' specified in the backend does not exist.
SECRETの設定が必要とのことです。
サイドペインのホスティングよりシークレットの編集をします。
GOOGLE_CLIENT_IDとGOOGLE_CLIENT_SECRETを設定して保存します。
保存したら再デプロイをして数分待ちますと…デプロイが完了しました!
URLにアクセスするとローカルのログインページが表示されています。
ただしGoogleでサインインしようとするとエラーになります。
これはcallbackとlogoutのURL設定が本番用にされていないためです。
amplify/auth/resource.ts
を更新してgit pushしましょう。
import { defineAuth, secret } from '@aws-amplify/backend';
/**
* Define and configure your auth resource
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
*/
export const auth = defineAuth({
loginWith: {
email: true,
externalProviders: {
google: {
clientId: secret('GOOGLE_CLIENT_ID'),
clientSecret: secret('GOOGLE_CLIENT_SECRET'),
scopes: ['email']
},
callbackUrls: [
'http://localhost:5173/',
// 追記
'https://master.d2gqzvqcw33vpq.amplifyapp.com/'
],
logoutUrls: [
'http://localhost:5173/',
//追記
'https://master.d2gqzvqcw33vpq.amplifyapp.com/'
],
},
},
});
自動でデプロイが走りこれでいけるか?と思いログインをすると、Googleさんに怒られました。
アクセスをブロック: このアプリのリクエストは無効です
これはリダイレクトURLの設定が間違っているときにおこるらしいです。
Cognitoを確認すると先ほどのSandbox版とは別に本番用のユーザープールができています。
そのため、Googleの設定を置き換える必要があります。
承認済みの JavaScript 生成元と承認済みのリダイレクト URIを本番用のCognitoのドメインで置き換えて保存します。
本番URLでGoogleでサインインできることを確認して終了です。
すこしつまづいたところもありましたが、よくある認証機能をコードの記述なしで作成できるので、ぱっと何か作りたい時に向いていると思いました。
ソースコードはgithubに公開していますので、ご参照ください。
https://github.com/qlitre/react-amplify-cognito-gen2