Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 163 additions & 30 deletions airbyte-integrations/connectors/source-gmail/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -248,19 +248,42 @@ definitions:
type: InlineSchemaLoader
schema:
$ref: "#/schemas/threads_details"
jwt_authenticator:
type: JwtAuthenticator
secret_key: "{{ json_loads(config['credentials']['service_account_info'])['private_key'] }}"
algorithm: "RS256"
token_duration: 3600
jwt_payload:
aud: "{{ json_loads(config['credentials']['service_account_info'])['token_uri'] }}"
iss: "{{ json_loads(config['credentials']['service_account_info'])['client_email'] }}"
additional_jwt_payload:
scope: "https://www.googleapis.com/auth/gmail.readonly"
oauth_authenticator:
type: OAuthAuthenticator
refresh_request_body: {}
token_refresh_endpoint: https://accounts.google.com/o/oauth2/token
grant_type: refresh_token
client_id: '{{ config["credentials"]["client_id"] }}'
client_secret: '{{ config["credentials"]["client_secret"] }}'
refresh_token: '{{ config["credentials"]["client_refresh_token"] }}'
jwt_profile_assertion_oauth_authenticator:
type: OAuthAuthenticator
token_refresh_endpoint: https://oauth2.googleapis.com/token
refresh_request_headers:
Content-Type: application/x-www-form-urlencoded
use_profile_assertion: true
profile_assertion:
$ref: "#/definitions/jwt_authenticator"
authenticator:
type: SelectiveAuthenticator
authenticator_selection_path: ["credentials", "auth_type"]
authenticators:
Client: "#/definitions/oauth_authenticator"
Service: "#/definitions/jwt_profile_assertion_oauth_authenticator"
base_requester:
type: HttpRequester
url_base: https://gmail.googleapis.com/gmail/v1/users/me/
authenticator:
type: OAuthAuthenticator
client_id: "{{ config[\"client_id\"] }}"
grant_type: refresh_token
client_secret: "{{ config[\"client_secret\"] }}"
refresh_token: "{{ config[\"client_refresh_token\"] }}"
expires_in_name: expires_in
access_token_name: access_token
refresh_request_body: {}
token_refresh_endpoint: https://accounts.google.com/o/oauth2/token
authenticator: "#/definitions/authenticator"

streams:
- $ref: "#/definitions/streams/profile"
Expand All @@ -278,36 +301,146 @@ spec:
type: object
$schema: http://json-schema.org/draft-07/schema#
required:
- client_id
- client_secret
- client_refresh_token
- credentials
properties:
client_id:
type: string
name: client_id
credentials:
type: object
title: Authentication
description: >-
Credentials for connecting to the Gmail API
order: 0
title: OAuth Client ID
airbyte_secret: true
client_secret:
type: string
name: client_secret
order: 1
title: OAuth Client Secret
airbyte_secret: true
client_refresh_token:
type: string
order: 2
title: Refresh token
airbyte_secret: true
oneOf:
- title: Authenticate via Google (OAuth)
type: object
required:
- auth_type
- client_id
- client_secret
- client_refresh_token
properties:
auth_type:
type: string
const: Client
client_id:
title: Client ID
type: string
description: "Enter your Google application's Client ID. See <a href='https://developers.google.com/identity/protocols/oauth2'>Google's documentation</a> for more information."
airbyte_secret: true
client_secret:
title: Client Secret
type: string
description: "Enter your Google application's Client Secret. See <a href='https://developers.google.com/identity/protocols/oauth2'>Google's documentation</a> for more information."
airbyte_secret: true
client_refresh_token:
title: Refresh Token
type: string
description: "Enter your Google application's refresh token. See <a href='https://developers.google.com/identity/protocols/oauth2'>Google's documentation</a> for more information."
airbyte_secret: true
- title: Service Account Key Authentication
type: object
required:
- auth_type
- service_account_info
properties:
auth_type:
type: string
const: Service
service_account_info:
type: string
title: Service Account Information.
description: 'The JSON key of the service account to use for authorization. Read more <a href="https://cloud.google.com/iam/docs/creating-managing-service-account-keys#creating_service_account_keys">here</a>.'
airbyte_secret: true
examples:
- '{ "type": "service_account", "project_id": YOUR_PROJECT_ID, "private_key_id": YOUR_PRIVATE_KEY, ... }'
include_spam_and_trash:
type: boolean
description: >-
Include drafts/messages from SPAM and TRASH in the results. Defaults
to false.
title: Include Spam & Trash
default: false
order: 3
order: 1
additionalProperties: true
config_normalization_rules:
type: ConfigNormalizationRules
config_migrations:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember this works fine, did you have the chance to manually test it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prerelease 0.0.52-preview.5480df5 was built and tested via version pinning in Cloud. The OAuth button renders correctly and the oneOf dropdown shows both auth types. The config migration structure is modeled after other connectors that use ConfigMigration with ConfigAddFields + ConfigRemoveFields.

One limitation we found: client_id/client_secret field hiding behind the OAuth button couldn't be fully verified via prerelease because the global cloud_registry.json still points to v0.0.49 (which has no advanced_auth). The prerelease per-version registry JSON has the correct advanced_auth (structurally identical to source-google-sheets), so field hiding should work once the connector is officially published.

- type: ConfigMigration
description: Migrate top-level OAuth fields into a nested credentials object.
transformations:
- type: ConfigAddFields
fields:
- type: AddedFieldDefinition
path:
- credentials
- auth_type
value: "Client"
- type: AddedFieldDefinition
path:
- credentials
- client_id
value: "{{ config['client_id'] }}"
- type: AddedFieldDefinition
path:
- credentials
- client_secret
value: "{{ config['client_secret'] }}"
- type: AddedFieldDefinition
path:
- credentials
- client_refresh_token
value: "{{ config['client_refresh_token'] }}"
condition: "{{ config.get('client_id') is not none and config.get('credentials') is none }}"
- type: ConfigRemoveFields
field_pointers:
- - client_id
- - client_secret
- - client_refresh_token
Comment on lines +395 to +397
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these array of arrays?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, do we need to remove them? I liked the idea that we could just pin the previous version.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — field_pointers expects an array of field pointers, where each field pointer is itself an array of path segments. In YAML, - - client_id represents [["client_id"]]. If you had a nested field like credentials.client_id, it would be:

field_pointers:
  - - credentials
    - client_id

This is the standard format used by ConfigRemoveFields in the CDK.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal is a cleanup step — after ConfigAddFields copies the values into credentials.client_id etc., the old top-level fields become stale duplicates. Without removal, the migrated config would have both config.client_id and config.credentials.client_id with the same value, which could be confusing.

That said, the removal only runs on configs that still have the old top-level format (guarded by the condition), so it's safe. And pinning the previous version for rollback would still work since the migration only triggers on old-format configs — configs that were already migrated wouldn't be affected.

This is ultimately a design choice for Serhii Lazebnyi (@lazebnyi) to decide on — happy to remove ConfigRemoveFields if you prefer keeping the stale top-level fields for extra safety.

condition: "{{ config.get('credentials') is not none }}"
advanced_auth:
auth_flow_type: oauth2.0
predicate_key:
- credentials
- auth_type
predicate_value: Client
oauth_config_specification:
oauth_connector_input_specification:
scopes:
- scope: "https://www.googleapis.com/auth/gmail.readonly"
consent_url: "https://accounts.google.com/o/oauth2/v2/auth?{{client_id_param}}&{{redirect_uri_param}}&response_type=code&{{scopes_param}}&access_type=offline&{{state_param}}&include_granted_scopes=true&prompt=consent"
access_token_url: "https://oauth2.googleapis.com/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}&{{redirect_uri_param}}&grant_type=authorization_code"
extract_output:
- refresh_token
complete_oauth_output_specification:
type: object
additionalProperties: false
properties:
refresh_token:
type: string
path_in_connector_config:
- credentials
- client_refresh_token
complete_oauth_server_input_specification:
type: object
additionalProperties: false
properties:
client_id:
type: string
client_secret:
type: string
complete_oauth_server_output_specification:
type: object
additionalProperties: false
properties:
client_id:
type: string
path_in_connector_config:
- credentials
- client_id
client_secret:
type: string
path_in_connector_config:
- credentials
- client_secret

metadata:
autoImportSchema:
Expand Down
2 changes: 1 addition & 1 deletion airbyte-integrations/connectors/source-gmail/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ data:
connectorSubtype: api
connectorType: source
definitionId: f7833dac-fc18-4feb-a2a9-94b22001edc6
dockerImageTag: 0.0.50
dockerImageTag: 0.0.52
dockerRepository: airbyte/source-gmail
githubIssueLabel: source-gmail
icon: icon.svg
Expand Down
9 changes: 6 additions & 3 deletions docs/integrations/sources/gmail.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ Gmail is the email service provided by Google.

| Input | Type | Description | Default Value |
|-------|------|-------------|---------------|
| `client_id` | `string` | OAuth Client ID. | |
| `client_secret` | `string` | OAuth Client Secret. | |
| `client_refresh_token` | `string` | Refresh token. | |
| `credentials` | `object` | Authentication. Credentials for connecting to the Gmail API. | |
| `credentials.client_id` | `string` | Client ID. Enter your Google application's Client ID. See Google's documentation for more information. | |
| `credentials.client_secret` | `string` | Client Secret. Enter your Google application's Client Secret. See Google's documentation for more information. | |
| `credentials.client_refresh_token` | `string` | Refresh Token. Enter your Google application's refresh token. See Google's documentation for more information. | |
| `credentials.service_account_info` | `string` | Service Account Information. The JSON key of the service account to use for authorization. | |
| `include_spam_and_trash` | `boolean` | Include Spam &amp; Trash. Include drafts/messages from SPAM and TRASH in the results. Defaults to false. | false |

Note that this connector uses the Google API OAuth2.0 for authentication. To get started, follow the steps [here](https://developers.google.com/gmail/api/auth/web-server#create_a_client_id_and_client_secret) to retrieve `client_id` and `client_secret`. See [here](https://developers.google.com/identity/protocols/oauth2/web-server) for more detailed guide on the OAuth flow to retrieve the `client_refresh_token`.
Expand All @@ -33,6 +35,7 @@ Note that this connector uses the Google API OAuth2.0 for authentication. To get

| Version | Date | Pull Request | Subject |
|------------------|-------------------|--------------|----------------|
| 0.0.52 | 2026-04-03 | [76065](https://github.com/airbytehq/airbyte/pull/76065) | Add OAuth flow with credentials wrapper and config migration |
| 0.0.50 | 2026-03-24 | [75387](https://github.com/airbytehq/airbyte/pull/75387) | Update dependencies |
| 0.0.49 | 2026-03-10 | [74532](https://github.com/airbytehq/airbyte/pull/74532) | Update dependencies |
| 0.0.48 | 2026-03-03 | [74205](https://github.com/airbytehq/airbyte/pull/74205) | Update dependencies |
Expand Down
Loading