> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Google OAuth

> Create a Google OAuth client, register Portal's redirect URI, and let your users sign in with Google.

Portal handles the OAuth exchange with Google and hands your app a token once the user has consented.

## Step 1: Create the OAuth client in Google Cloud Console

1. Open the [Google Cloud Console](https://console.cloud.google.com/) and select
   or create a project.

2. Go to **APIs & Services > OAuth consent screen** and configure it if you have
   not already. Portal requests the `openid`, `email`, and `profile` scopes, all
   of which are non-sensitive, so this does not require Google verification for
   internal or standard use.

3. Go to **APIs & Services > Credentials** and click
   **Create Credentials > OAuth client ID**.

   <Frame>
     <img src="https://mintcdn.com/portal-003221ec/UBGZngsyXL4rYrpA/images/authentication/google-create-credentials.png?fit=max&auto=format&n=UBGZngsyXL4rYrpA&q=85&s=7597ec6e0924d519ecfd0bc5caf556bd" alt="Google Cloud Console Credentials page with the Create Credentials menu open on OAuth client ID" width="3456" height="870" data-path="images/authentication/google-create-credentials.png" />
   </Frame>

4. For **Application type**, choose **Web application**.

5. Give it a name you will recognize, for example `Portal Authentication`.

   <Frame>
     <img src="https://mintcdn.com/portal-003221ec/UBGZngsyXL4rYrpA/images/authentication/google-application-type.png?fit=max&auto=format&n=UBGZngsyXL4rYrpA&q=85&s=be3222b270b2937fb52ecb5e6cc46567" alt="Create OAuth client ID form with Application type set to Web application and a name entered" width="1566" height="744" data-path="images/authentication/google-application-type.png" />
   </Frame>

6. Under **Authorized redirect URIs**, click **Add URI** and add the Portal
   callback URL for each of your environments:

   ```
   https://api.portalhq.io/api/v3/auth/oauth/callback/<DEVELOPMENT_AUTH_ENVIRONMENT_ID>
   https://api.portalhq.io/api/v3/auth/oauth/callback/<PRODUCTION_AUTH_ENVIRONMENT_ID>
   ```

   <Frame>
     <img src="https://mintcdn.com/portal-003221ec/UBGZngsyXL4rYrpA/images/authentication/google-redirect-uris.png?fit=max&auto=format&n=UBGZngsyXL4rYrpA&q=85&s=b5dad516cbe0c11a86378500e97879d1" alt="Authorized redirect URIs section with a Portal callback URL added for each environment" width="994" height="560" data-path="images/authentication/google-redirect-uris.png" />
   </Frame>

7. Click **Create**, then copy the **Client ID** and **Client secret**.

<Note>
  You do not need to add anything under **Authorized JavaScript origins**. The
  OAuth exchange happens server to server between Portal and Google, not in your
  user's browser.
</Note>

### The redirect URI Google needs

The Google OAuth process should redirect to **Portal**,
which verifies the sign-in with Google and then redirects the user on to your
Redirect URL. The URI you register with Google is therefore a Portal URL:

```
https://api.portalhq.io/api/v3/auth/oauth/callback/<AUTH_ENVIRONMENT_ID>
```

Replace `<AUTH_ENVIRONMENT_ID>` with the Auth Environment ID from
**Authentication > Configure**. Because each environment has a different Auth
Environment ID, **each environment needs its own entry** in Google's authorized
redirect URIs. If you use Development and Production, register both.

<Warning>
  Google requires the redirect URI to match exactly. No trailing slash, and
  the Auth Environment ID has to be exact. A mismatch shows the user a
  `redirect_uri_mismatch` error from Google before they ever reach your app.
</Warning>

## Step 2: Enter the credentials in Portal

**Information from Google (to enter in Portal):**

* **Client ID**: the OAuth client identifier, ending in
  `.apps.googleusercontent.com`
* **Client secret**: the OAuth client secret

Step 1: In the dashboard, click **Configure** in the left sidebar, under
Authentication, and select the environment.

Step 2: In the **Google OAuth** section, turn on the toggle.

Step 3: Paste the **Client ID** and **Client secret**, then save.

<Frame>
  <img src="https://mintcdn.com/portal-003221ec/UBGZngsyXL4rYrpA/images/authentication/google-oauth-section.png?fit=max&auto=format&n=UBGZngsyXL4rYrpA&q=85&s=77f2bc1e430ecc89851cd13176efe98e" alt="Google OAuth section with the enable toggle and the Client ID and Client secret fields" width="1050" height="648" data-path="images/authentication/google-oauth-section.png" />
</Frame>

Both fields are write-only. After saving, each shows that a value is stored rather
than the value itself. To rotate the secret, paste the new one and save again. To
leave it unchanged, leave the field empty.

<Note>
  If you use the same Google OAuth client for Development and Production, enter the
  same Client ID and secret in both environments. The credentials are stored per
  environment.
</Note>

## Step 3: Sign a user in

### Get the authorize URL

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/auth/oauth/urls?redirectUrl=https%3A%2F%2Fexample.com%2Fcallback' \
  --header 'x-portal-auth-environment-id: <AUTH_ENVIRONMENT_ID>'
```

```json theme={null}
{
  "data": {
    "google": "https://accounts.google.com/o/oauth2/v2/auth?client_id=..."
  },
  "metadata": null
}
```

The response contains a `google` key only if Google is enabled on the
environment. `redirectUrl` must be URL-encoded in the query string and must
exactly match one of your Redirect URLs.

### Send the user to Google

Open `data.google` in a browser. The user picks their Google account and consents.

Google returns them to Portal, Portal verifies the sign-in, and Portal redirects
them to your Redirect URL:

```
https://example.com/callback?token=<TOKEN>&login_type=GOOGLE
```

<Note>
  Magic links use an `authMethod` query parameter and OAuth uses `login_type`. If
  you support both, read whichever is present rather than assuming one name.
</Note>

### Exchange the token

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/auth/oauth/tokens \
  --header 'x-portal-auth-environment-id: <AUTH_ENVIRONMENT_ID>' \
  --header 'Content-Type: application/json' \
  --data '{ "token": "<TOKEN>" }'
```

```json theme={null}
{
  "data": {
    "endUserId": "clx1enduser00000000000000",
    "clientSessionToken": "b7c1f0a2-3d4e-5f60-8a91-2b3c4d5e6f70",
    "userJwt": null,
    "totpLink": null
  },
  "metadata": null
}
```

If the environment requires a second factor, `clientSessionToken` is `null` and
`userJwt` is set. See
[Two-factor authentication](/resources/authentication/two-factor-authentication).

## Handle a failed sign-in

If the user cancels, or anything in the exchange fails, Portal still redirects
them to your Redirect URL, with an error instead of a token:

```
https://example.com/callback?error=oauth_failed
```

## Google Drive backups are separate

If you also use Google Drive as a wallet backup method, that is an independent
authorization with its own scopes, requested by the SDK when the user backs up.
Signing in with Google here does not grant Drive access, and it does not replace
the setup described in the Google Drive backup guides.

## Next steps

<Card title="Apple OAuth" icon="apple" href="/resources/authentication/apple-oauth">
  Add Sign in with Apple alongside Google.
</Card>

<Card title="API reference" icon="code" href="/api-reference/oauth/get-the-oauth-authorize-urls">
  Full reference for the OAuth endpoints.
</Card>
