# Google Login研究─React & React Native
## Google配置頁面及文件
> 管理憑證和OAuth同意畫面:[Google API Console](https://console.cloud.google.com/)
> Google OAuth文件:[Using OAuth 2.0 to Access Google APIs | Authorization | Google Developers](https://developers.google.com/identity/protocols/oauth2)
---
## React (Web App)
> - [The guide to adding Google login to your React app | Blog](https://blog.logrocket.com/guide-adding-google-login-react-app/)
> - [`@react-oauth/google` README | Github](https://github.com/MomenSherif/react-oauth#readme)
### 流程概述
*細節請參考上方第一篇文章連結
- 在[Google API Console](https://console.cloud.google.com/)選擇一專案,設定好「OAuth同意畫面」,這邊的「應用程式名稱」和「使用者者支援電子郵件」會顯示在同意畫面上。
- 呈上,繼續前往憑證頁面,選擇「建立憑證 > OAuth Client ID」,建立供「網頁應用程式」使用的Client ID,下載JSON,在撰寫程式時可以直接使用。
- 上述皆設定完成後使用`npm install @react-oauth/google`,接著完成該套件的配置及程式碼實作。
- 當使用者於同意畫面選擇同意,及代表同意App存取資料,此時App會拿到`access_token`:
```json
{
"access_token": "ya29.a0Ael9sCPzUXc2CPMDNF2QwG478YRBQFrKHGMRWIQJUNiy8KV9DaBSfk04GvShTLcv7w3zPXSYV-mLz8u3Knl6wFpMEuwKIGSqIswoI7ZPDE_bFkoUEat91CDcx03KfnSfUsj-acyVzqbUH47cbtKXbrkeXyGDaCgYKAeoSARMSFQF4udJhPooiYqwCRQ0ZvLfMLCIxlA0163",
"expires_in": 3599,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg2OTY5YWVjMzdhNzc4MGYxODgwNzg3NzU5M2JiYmY4Y2Y1ZGU1Y2UiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIxMzEyNzg1NDQyNjMtbGlxNmYwdHVhOXVzamUwYzBrMmMxbHVtbjl1YjcxcnAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIxMzEyNzg1NDQyNjMtbGlxNmYwdHVhOXVzamUwYzBrMmMxbHVtbjl1YjcxcnAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDE4NjY5NTkxODAyMzgyMzk5NTciLCJoZCI6Iml0cnVzdG1hY2hpbmVzLmNvbSIsImVtYWlsIjoib2xpdmUud3VAaXRydXN0bWFjaGluZXMuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJYdVhncFdRNDYybG5xTWY4dXVkdVl3IiwibmFtZSI6Ik9saXZlIFd1IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hL0FHTm15eGFQZV9kdU5aUGtDMk0zeHBxd01iUlhVQnAzNDNwZzVsWVViWDJFPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6Ik9saXZlIiwiZmFtaWx5X25hbWUiOiJXdSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNjgyNTYzNTQzLCJleHAiOjE2ODI1NjcxNDN9.D7BUSdRcezYHbVf7_-mrCRwjs4CwHDXMFii5hxpXm_u6VoqFTHSU3aweZeqKA2qQIBXXAlBK5zDZkC6RYiojpnfV-JLTAfdsS9x6g3VlMg98jL30rPlWI1_XFsuc7CftXuuECdkXeVnKDYRKsbvr2FWbP_itNS4scLZHiWqv0vPdyaOrzJV-lW7-3nxncp3I1vSOVJjCzT1mrjBdYvjMAT1oGBsqjlHNx-qSleF8jS_6fd9nReXpebI8vckCOgfuu063GOMqi84-CuOFjK-Wb3dXYUwWqg071bRpDiS3rmh8kQAIaCkNGBEEL9ptXXBz0_Y4DCLA1G9UwHqUrRUfJg",
"refresh_token": "1//0eyMrbkU5a3u3CgYIARAAGA4SNwF-L9IrhK-GYLhuBOrWaXTxQCoj1ifwYTFZRp9-N2PkJDUD_jqzRAF6N0e-VjEM5wk7jxR-jGc",
"scope": "https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email",
"token_type": "Bearer",
}
```
*`expires_in`單位為秒數,效期1小時
*`refresh_token`效期為200天
- 透過`access_token`,App可以向Google的Resource Server存取使用者允許的資料:
```json
{
"id": "101866959180238239957",
"email": "olive.wu@itrustmachines.com",
"verified_email": true,
"name": "Olive Wu",
"given_name": "Olive",
"family_name": "Wu",
"picture": "https://lh3.googleusercontent.com/a/AGNmyxaPe_duNZPkC2M3xpqwMbRXUBp343pg5lYUbX2E=s96-c",
"locale": "en",
"hd": "itrustmachines.com "
}
```
- App可以依照需求提供所需的權限清單(Scope),Authorization Server(即Google)會依照清單尋求使用者的同意。
可以在[Google API Console](https://console.cloud.google.com/)的「OAuth同意畫面 > 範圍」進行Scope設定。
---
## React Native (Mobile App)
> - [Authentication with Google and AuthSession API | Expo](https://docs.expo.dev/guides/google-authentication/)
> - [Expo Auth Session - Login with Google in React Native Apps includes Refreshing Tokens and Logout | Youtube](https://www.youtube.com/watch?v=oPTGoJw_Tik&t=2693s&ab_channel=MissCoding)
### 流程概述
*目前只有測試Android功能
- 在[Google API Console](https://console.cloud.google.com/)選擇一專案,設定OAuth同意畫面。
- 至憑證頁面「建立憑證 > OAuth Client ID」,創建供「Android」使用的Client ID,此處需要填寫「套件名稱」及「SHA-1 憑證指紋」。
1. 填寫`app.json`中`android.package`的package name,若沒有則新增於檔案中。若選擇建立iOS的Client ID請在`ios.bundleIdentifier`下新增。
```json
{
"expo": {
"android": {
"package": "com.test.google",
}
},
}
```
2. 取得SHA-1 憑證指紋:
- `npm install -g eas-cli`
- 執行`eas build:configure`並選擇"ALL"以產生`eas.json`。
- 執行`eas credentials -p android`並follow[此章節](https://docs.expo.dev/guides/google-authentication#create-client-ids)的SHA-1 certificate fingerprint步驟。
- 完成後複製SHA1 Fingerprint至憑證頁面貼上。
- 完成[AuthSession API相關配置及實作](https://docs.expo.dev/guides/google-authentication#using-authsession-api)。
- 使用者在手機App上點選登入按鈕,會在App中開啟內建瀏覽器(WebView)顯示同意畫面。
使用者同意存取後會返回App,且App會取得`accessToken`以向Google拿取使用者資料。
```json
{
"type": "success",
"error": null,
"url": "exp://192.168.30.137:19000/--/expo-auth-session#state=6icSHYQq1Z&access_token=ya29.a0Ael9sCOgPNMti67vlIskLeCPhb3v22RvcIvKJ2auhN4Huz2Xv5OITshRwQ2DAdVbzqZtmYD4fKx9Q6fvSHAcEUBfTnUQow4qNPaxU9Ej_Cx7JBOrkeqFslPVZX5j2TIZ1pGbfgZJAmmu00tL4_C-YYOJWDlNaCgYKAX8SARMSFQF4udJhYhSwwmWznZ0xDIWeIpIGYQ0163&token_type=Bearer&expires_in=3599&scope=email%20profile%20openid%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email&authuser=1&hd=itrustmachines.com&prompt=none",
"params": {
"exp://192.168.30.137:19000/--/expo-auth-session": "",
"state": "6icSHYQq1Z",
"access_token": "ya29.a0Ael9sCOgPNMti67vlIskLeCPhb3v22RvcIvKJ2auhN4Huz2Xv5OITshRwQ2DAdVbzqZtmYD4fKx9Q6fvSHAcEUBfTnUQow4qNPaxU9Ej_Cx7JBOrkeqFslPVZX5j2TIZ1pGbfgZJAmmu00tL4_C-YYOJWDlNaCgYKAX8SARMSFQF4udJhYhSwwmWznZ0xDIWeIpIGYQ0163",
"token_type": "Bearer",
"expires_in": "3599",
"scope": "email profile openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"authuser": "1",
"hd": "itrustmachines.com",
"prompt": "none"
},
"authentication": {
"accessToken": "ya29.a0Ael9sCOgPNMti67vlIskLeCPhb3v22RvcIvKJ2auhN4Huz2Xv5OITshRwQ2DAdVbzqZtmYD4fKx9Q6fvSHAcEUBfTnUQow4qNPaxU9Ej_Cx7JBOrkeqFslPVZX5j2TIZ1pGbfgZJAmmu00tL4_C-YYOJWDlNaCgYKAX8SARMSFQF4udJhYhSwwmWznZ0xDIWeIpIGYQ0163",
"tokenType": "Bearer",
"expiresIn": "3599",
"scope": "email profile openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"state": "6icSHYQq1Z",
"issuedAt": 1682490920
},
"errorCode": null
}
```
- 使用[Development builds](https://docs.expo.dev/develop/development-builds/introduction/?redirected)運行,並且在程式碼中的`promptAsync()`設定`{ useProxy: false }`:
```javascript
const [request, response, promptAsync] = Google.useAuthRequest(googleConfig)
...
return (
<Button
title="Sign in with Google"
disabled={!request}
onPress={() => {
promptAsync({ useProxy: false })
}}
/>
)
```
在使用Google OAuth功能時,便不會另外導轉至該頁面。

---
## 補充
- [Google API Console](https://console.cloud.google.com/) > 「OAuth同意畫面」
發布狀態為「測試中」時,需要將測試使用者加入清單才能進行測試,且上限為100人。

- #### [Security considerations](https://docs.expo.dev/versions/latest/sdk/auth-session#security-considerations)
**Never put any secret keys inside of your application code**, there is no secure way to do this! Instead, you should store your secret key(s) on a server and expose an endpoint that makes API calls for your client and passes the data back.