Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/azfar-imtiaz/PayPulse-Cloud/llms.txt

Use this file to discover all available pages before exploring further.

Gmail authorization in PayPulse is initiated entirely on the iOS device. The backend never participates in the OAuth authorization code exchange — it only receives the resulting tokens.

Google Sign-In SDK

The iOS app uses the Google Sign-In SDK for iOS. The SDK handles:
  • Presenting the native Google consent screen.
  • Managing the OAuth authorization code exchange with Google’s servers.
  • Returning an access token, optional refresh token, and token metadata to the app.
The app is configured with an iOS client ID from Google Cloud Console. Because this is a native mobile client, it is classified as a public OAuth client — no client secret is required or used.
iOS OAuth credentials (client ID) are separate from server-side OAuth credentials. The iOS client ID is stored in AWS Secrets Manager under Google-OAuth-Client-ID and is read by Lambda functions when they need to refresh tokens. No client secret exists for the iOS client; Google’s token endpoint accepts refresh requests from public clients without one.

Native iOS OAuth flow

1

User initiates Gmail connection

The user taps the “Connect Gmail” button in the PayPulse app. The app calls GIDSignIn.sharedInstance.signIn(...) with the gmail.readonly scope.
2

Google consent screen

The Google Sign-In SDK opens a secure in-app browser session (ASWebAuthenticationSession) displaying Google’s consent screen. The user reviews the requested permissions and approves.
3

Tokens returned to the app

Google’s servers exchange the authorization code for tokens and return them to the SDK. The app receives an access_token, a refresh_token (on first authorization), expires_in, and the granted scope.
4

Tokens sent to backend

The app immediately sends the tokens to the backend via the store-tokens endpoint.

The /v1/auth/gmail-tokens endpoint

The iOS app posts token data to this endpoint immediately after the user grants consent. The request must include a valid PayPulse JWT in the Authorization header. Method: POST
Path: /v1/auth/gmail-tokens
Authentication: Bearer JWT (from PayPulse login)

Request body

request body
{
  "access_token": "ya29.a0AfB_...",
  "refresh_token": "1//0gABC...",
  "expires_in": 3600,
  "scope": [
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile"
  ],
  "email": "user@gmail.com"
}
FieldTypeRequiredDescription
access_tokenstringYesShort-lived OAuth access token from Google Sign-In
refresh_tokenstringNoLong-lived refresh token; present on first authorization
expires_inintegerNoToken lifetime in seconds (defaults to 3600)
scopestring[]NoArray of granted OAuth scopes
emailstringNoUser’s Google email address
The endpoint also accepts application/x-www-form-urlencoded bodies for compatibility.

Response

success response (201)
{
  "message": "Gmail OAuth tokens stored successfully!",
  "data": {
    "google_email": "user@gmail.com",
    "scope": "https://www.googleapis.com/auth/gmail.readonly ...",
    "account_switch": false,
    "message": "First Gmail connection"
  }
}
The account_switch field is true when the user connects a different Google account than the one previously stored. The iOS app can use this to display a warning.

Gmail connection status in user profile

The GET /v1/user/me endpoint returns a gmail_account_connected boolean field that reflects whether the user has OAuth tokens stored in Secrets Manager:
user profile response
{
  "message": "User profile retrieved successfully",
  "data": {
    "name": "Jane Smith",
    "email": "jane@example.com",
    "created_on": "2024-11-01T10:00:00Z",
    "gmail_account_connected": true
  }
}
The iOS app uses gmail_account_connected to decide whether to show the “Connect Gmail” button or the connected Gmail address. The check is performed by looking up the secret gmail/user/{user_id} in Secrets Manager — if it exists, the account is considered connected.

Build docs developers (and LLMs) love