diff --git a/docs/connector-development/README.md b/docs/connector-development/README.md
index f1e6cb6f2d639..5248285f1f904 100644
--- a/docs/connector-development/README.md
+++ b/docs/connector-development/README.md
@@ -23,7 +23,7 @@ If you need support along the way, visit the [Slack channel](https://airbytehq.s
| Tool | Description |
| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Connector Builder](./connector-builder-ui/overview.md) | We recommend Connector Builder for developing a connector for an API source. If you’re using Airbyte Cloud, no local developer environment is required to create a new connection with the Connector Builder because you configure it directly in the Airbyte web UI. This tool guides you through creating and testing a connection. Refer to our [tutorial](./connector-builder-ui/tutorial.mdx) on the Connector Builder to guide you through the basics. |
-| [Low Code Connector Development Kit (CDK)](./config-based/low-code-cdk-overview.md) | This framework lets you build source connectors for HTTP API sources. The Low-code CDK is a declarative framework that allows you to describe the connector using a [YAML schema](./schema-reference) without writing Python code. It’s flexible enough to include [custom Python components](./config-based/advanced-topics.md#custom-components) in conjunction with this method if necessary. |
+| [Low Code Connector Development Kit (CDK)](./config-based/low-code-cdk-overview.md) | This framework lets you build source connectors for HTTP API sources. The Low-code CDK is a declarative framework that allows you to describe the connector using a [YAML schema](./schema-reference) without writing Python code. It’s flexible enough to include [custom Python components](./config-based/advanced-topics/custom-components.md) in conjunction with this method if necessary. |
| [Python Connector Development Kit (CDK)](./cdk-python/basic-concepts.md) | While this method provides the most flexibility to developers, it also requires the most code and maintenance. This library provides classes that work out-of-the-box for most scenarios you’ll encounter along with the generators to make the connector scaffolds for you. We maintain an [in-depth guide](./tutorials/custom-python-connector/0-getting-started.md) to building a connector using the Python CDK. |
| [Java CDK](./tutorials/building-a-java-destination.md) | If you're bulding a source or a destination against a traditional database (not an HTTP API, not a vector database), you should use the Java CDK instead. |
diff --git a/docs/connector-development/config-based/advanced-topics.md b/docs/connector-development/config-based/advanced-topics.md
deleted file mode 100644
index 2bd86c58dc701..0000000000000
--- a/docs/connector-development/config-based/advanced-topics.md
+++ /dev/null
@@ -1,321 +0,0 @@
-# Advanced Topics
-
-## Object instantiation
-
-This section describes the object that are to be instantiated from the YAML definition.
-
-If the component is a literal, then it is returned as is:
-
-```
-3
-```
-
-will result in
-
-```
-3
-```
-
-If the component definition is a mapping with a "type" field,
-the factory will lookup the [CLASS_TYPES_REGISTRY](https://github.com/airbytehq/airbyte-python-cdk/blob/main//airbyte_cdk/sources/declarative/parsers/class_types_registry.py) and replace the "type" field by "class_name" -> CLASS_TYPES_REGISTRY[type]
-and instantiate the object from the resulting mapping
-
-If the component definition is a mapping with neither a "class_name" nor a "type" field,
-the factory will do a best-effort attempt at inferring the component type by looking up the parent object's constructor type hints.
-If the type hint is an interface present in [DEFAULT_IMPLEMENTATIONS_REGISTRY](https://github.com/airbytehq/airbyte-python-cdk/blob/main//airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py),
-then the factory will create an object of its default implementation.
-
-If the component definition is a list, then the factory will iterate over the elements of the list,
-instantiate its subcomponents, and return a list of instantiated objects.
-
-If the component has subcomponents, the factory will create the subcomponents before instantiating the top level object
-
-```
-{
- "type": TopLevel
- "param":
- {
- "type": "ParamType"
- "k": "v"
- }
-}
-```
-
-will result in
-
-```
-TopLevel(param=ParamType(k="v"))
-```
-
-More details on object instantiation can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=factory#airbyte_cdk.sources.declarative.parsers.factory.DeclarativeComponentFactory).
-
-## $parameters
-
-Parameters can be passed down from a parent component to its subcomponents using the $parameters key.
-This can be used to avoid repetitions.
-
-Schema:
-
-```yaml
-"$parameters":
- type: object
- additionalProperties: true
-```
-
-Example:
-
-```yaml
-outer:
- $parameters:
- MyKey: MyValue
- inner:
- k2: v2
-```
-
-This the example above, if both outer and inner are types with a "MyKey" field, both of them will evaluate to "MyValue".
-
-These parameters can be overwritten by subcomponents as a form of specialization:
-
-```yaml
-outer:
- $parameters:
- MyKey: MyValue
- inner:
- $parameters:
- MyKey: YourValue
- k2: v2
-```
-
-In this example, "outer.MyKey" will evaluate to "MyValue", and "inner.MyKey" will evaluate to "YourValue".
-
-The value can also be used for string interpolation:
-
-```yaml
-outer:
- $parameters:
- MyKey: MyValue
- inner:
- k2: "MyKey is {{ parameters['MyKey'] }}"
-```
-
-In this example, outer.inner.k2 will evaluate to "MyKey is MyValue"
-
-## References
-
-Strings can contain references to previously defined values.
-The parser will dereference these values to produce a complete object definition.
-
-References can be defined using a `#/{arg}` string.
-
-```yaml
-key: 1234
-reference: "#/key"
-```
-
-will produce the following definition:
-
-```yaml
-key: 1234
-reference: 1234
-```
-
-This also works with objects:
-
-```yaml
-key_value_pairs:
- k1: v1
- k2: v2
-same_key_value_pairs: "#/key_value_pairs"
-```
-
-will produce the following definition:
-
-```yaml
-key_value_pairs:
- k1: v1
- k2: v2
-same_key_value_pairs:
- k1: v1
- k2: v2
-```
-
-The $ref keyword can be used to refer to an object and enhance it with addition key-value pairs
-
-```yaml
-key_value_pairs:
- k1: v1
- k2: v2
-same_key_value_pairs:
- $ref: "#/key_value_pairs"
- k3: v3
-```
-
-will produce the following definition:
-
-```yaml
-key_value_pairs:
- k1: v1
- k2: v2
-same_key_value_pairs:
- k1: v1
- k2: v2
- k3: v3
-```
-
-References can also point to nested values.
-Nested references are ambiguous because one could define a key containing with `/`
-in this example, we want to refer to the limit key in the dict object:
-
-```yaml
-dict:
- limit: 50
-limit_ref: "#/dict/limit"
-```
-
-will produce the following definition:
-
-```yaml
-dict
-limit: 50
-limit-ref: 50
-```
-
-whereas here we want to access the `nested/path` value.
-
-```yaml
-nested:
- path: "first one"
-nested.path: "uh oh"
-value: "ref(nested.path)
-```
-
-will produce the following definition:
-
-```yaml
-nested:
- path: "first one"
-nested/path: "uh oh"
-value: "uh oh"
-```
-
-To resolve the ambiguity, we try looking for the reference key at the top-level, and then traverse the structs downward
-until we find a key with the given path, or until there is nothing to traverse.
-
-More details on referencing values can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=yamlparser#airbyte_cdk.sources.declarative.parsers.yaml_parser.YamlParser).
-
-## String interpolation
-
-String values can be evaluated as Jinja2 templates.
-
-If the input string is a raw string, the interpolated string will be the same.
-`"hello world" -> "hello world"`
-
-The engine will evaluate the content passed within `{{...}}`, interpolating the keys from context-specific arguments.
-The "parameters" keyword [see ($parameters)](#parameters) can be referenced.
-
-For example, some_object.inner_object.key will evaluate to "Hello airbyte" at runtime.
-
-```yaml
-some_object:
- $parameters:
- name: "airbyte"
- inner_object:
- key: "Hello {{ parameters.name }}"
-```
-
-Some components also pass in additional arguments to the context.
-This is the case for the [record selector](./understanding-the-yaml-file/record-selector.md), which passes in an additional `response` argument.
-
-Both dot notation and bracket notations (with single quotes ( `'`)) are interchangeable.
-This means that both these string templates will evaluate to the same string:
-
-1. `"{{ parameters.name }}"`
-2. `"{{ parameters['name'] }}"`
-
-In addition to passing additional values through the $parameters argument, macros can be called from within the string interpolation.
-For example,
-`"{{ max(2, 3) }}" -> 3`
-
-The macros and variables available in all possible contexts are documented in the [YAML Reference](./understanding-the-yaml-file/reference.md#variables).
-
-Additional information on jinja templating can be found at [https://jinja.palletsprojects.com/en/3.1.x/templates/#](https://jinja.palletsprojects.com/en/3.1.x/templates/#)
-
-## Component schema reference
-
-A JSON schema representation of the relationships between the components that can be used in the YAML configuration can be found [here](https://github.com/airbytehq/airbyte-python-cdk/blob/main/airbyte_cdk/sources/declarative/declarative_component_schema.yaml).
-
-## Custom components
-
-:::info
-Please help us improve the low code CDK! If you find yourself needing to build a custom component,please [create a feature request issue](https://github.com/airbytehq/airbyte/issues/new?assignees=&labels=type%2Fenhancement%2C+%2Cneeds-triage%2C+area%2Flow-code%2Fcomponents&template=feature-request.md&title=Low%20Code%20Feature:). If appropriate, we'll add it directly to the framework (or you can submit a PR)!
-
-If an issue already exist for the missing feature you need, please upvote or comment on it so we can prioritize the issue accordingly.
-:::
-
-Any built-in components can be overloaded by a custom Python class.
-To create a custom component, define a new class in a new file in the connector's module.
-The class must implement the interface of the component it is replacing. For instance, a pagination strategy must implement `airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy.PaginationStrategy`.
-The class must also be a dataclass where each field represents an argument to configure from the yaml file, and an `InitVar` named parameters.
-
-For example:
-
-```
-@dataclass
-class MyPaginationStrategy(PaginationStrategy):
- my_field: Union[InterpolatedString, str]
- parameters: InitVar[Mapping[str, Any]]
-
- def __post_init__(self, parameters: Mapping[str, Any]):
- pass
-
- def next_page_token(self, response: requests.Response, last_records: List[Mapping[str, Any]]) -> Optional[Any]:
- pass
-
- def reset(self):
- pass
-```
-
-This class can then be referred from the yaml file by specifying the type of custom component and using its fully qualified class name:
-
-```yaml
-pagination_strategy:
- type: "CustomPaginationStrategy"
- class_name: "my_connector_module.MyPaginationStrategy"
- my_field: "hello world"
-```
-
-### Custom Components that pass fields to child components
-
-There are certain scenarios where a child subcomponent might rely on a field defined on a parent component. For regular components, we perform this propagation of fields from the parent component to the child automatically.
-However, custom components do not support this behavior. If you have a child subcomponent of your custom component that falls under this use case, you will see an error message like:
-
-```
-Error creating component 'DefaultPaginator' with parent custom component source_example.components.CustomRetriever: Please provide DefaultPaginator.$parameters.url_base
-```
-
-When you receive this error, you can address this by defining the missing field within the `$parameters` block of the child component.
-
-```yaml
- paginator:
- type: "DefaultPaginator"
- <...>
- $parameters:
- url_base: "https://example.com"
-```
-
-## How the framework works
-
-1. Given the connection config and an optional stream state, the `PartitionRouter` computes the partitions that should be routed to read data.
-2. Iterate over all the partitions defined by the stream's partition router.
-3. For each partition,
- 1. Submit a request to the partner API as defined by the requester
- 2. Select the records from the response
- 3. Repeat for as long as the paginator points to a next page
-
-[connector-flow](./assets/connector-flow.png)
-
-## More readings
-
-- [Record selector](./understanding-the-yaml-file/record-selector.md)
-- [Partition routers](./understanding-the-yaml-file/partition-router.md)
-- [Source schema](https://github.com/airbytehq/airbyte-python-cdk/blob/main/airbyte_cdk/sources/declarative/declarative_component_schema.yaml)
diff --git a/docs/connector-development/config-based/advanced-topics/component-schema-reference.md b/docs/connector-development/config-based/advanced-topics/component-schema-reference.md
new file mode 100644
index 0000000000000..842291fa22a56
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/component-schema-reference.md
@@ -0,0 +1,3 @@
+# Component Schema Reference
+
+A JSON schema representation of the relationships between the components that can be used in the YAML configuration can be found [here](https://github.com/airbytehq/airbyte-python-cdk/blob/main/airbyte_cdk/sources/declarative/declarative_component_schema.yaml).
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/custom-components.md b/docs/connector-development/config-based/advanced-topics/custom-components.md
new file mode 100644
index 0000000000000..15bcc410e822f
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/custom-components.md
@@ -0,0 +1,58 @@
+# Custom Components
+
+:::info
+Please help us improve the low code CDK! If you find yourself needing to build a custom component,please [create a feature request issue](https://github.com/airbytehq/airbyte/issues/new?assignees=&labels=type%2Fenhancement%2C+%2Cneeds-triage%2C+area%2Flow-code%2Fcomponents&template=feature-request.md&title=Low%20Code%20Feature:). If appropriate, we'll add it directly to the framework (or you can submit a PR)!
+
+If an issue already exist for the missing feature you need, please upvote or comment on it so we can prioritize the issue accordingly.
+:::
+
+Any built-in components can be overloaded by a custom Python class.
+To create a custom component, define a new class in a new file in the connector's module.
+The class must implement the interface of the component it is replacing. For instance, a pagination strategy must implement `airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy.PaginationStrategy`.
+The class must also be a dataclass where each field represents an argument to configure from the yaml file, and an `InitVar` named parameters.
+
+For example:
+
+```
+@dataclass
+class MyPaginationStrategy(PaginationStrategy):
+ my_field: Union[InterpolatedString, str]
+ parameters: InitVar[Mapping[str, Any]]
+
+ def __post_init__(self, parameters: Mapping[str, Any]):
+ pass
+
+ def next_page_token(self, response: requests.Response, last_records: List[Mapping[str, Any]]) -> Optional[Any]:
+ pass
+
+ def reset(self):
+ pass
+```
+
+This class can then be referred from the yaml file by specifying the type of custom component and using its fully qualified class name:
+
+```yaml
+pagination_strategy:
+ type: "CustomPaginationStrategy"
+ class_name: "my_connector_module.MyPaginationStrategy"
+ my_field: "hello world"
+```
+
+### Custom Components that pass fields to child components
+
+There are certain scenarios where a child subcomponent might rely on a field defined on a parent component. For regular components, we perform this propagation of fields from the parent component to the child automatically.
+However, custom components do not support this behavior. If you have a child subcomponent of your custom component that falls under this use case, you will see an error message like:
+
+```
+Error creating component 'DefaultPaginator' with parent custom component source_example.components.CustomRetriever: Please provide DefaultPaginator.$parameters.url_base
+```
+
+When you receive this error, you can address this by defining the missing field within the `$parameters` block of the child component.
+
+```yaml
+ paginator:
+ type: "DefaultPaginator"
+ <...>
+ $parameters:
+ url_base: "https://example.com"
+```
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/how-framework-works.md b/docs/connector-development/config-based/advanced-topics/how-framework-works.md
new file mode 100644
index 0000000000000..8537770ff7168
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/how-framework-works.md
@@ -0,0 +1,10 @@
+# How the Framework Works
+
+1. Given the connection config and an optional stream state, the `PartitionRouter` computes the partitions that should be routed to read data.
+2. Iterate over all the partitions defined by the stream's partition router.
+3. For each partition,
+ 1. Submit a request to the partner API as defined by the requester
+ 2. Select the records from the response
+ 3. Repeat for as long as the paginator points to a next page
+
+[connector-flow](../assets/connector-flow.png)
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/oauth.md b/docs/connector-development/config-based/advanced-topics/oauth.md
new file mode 100644
index 0000000000000..fbc4925802b0d
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/oauth.md
@@ -0,0 +1,1227 @@
+# OAuth Authentication Methods
+At Aribyte, we offer two options for authentication using `OAuth2.0`:
+
+1. **Airbyte's Own OAuth Application**: With this option, you do not need to create your own OAuth application with the data provider. This is typically applied to `Airbyte Cloud` customers as a `pick-and-use` scenario.
+2. **Declarative OAuth2.0**: This option requires you to provide your own `client id` and `client secret` (parameters may vary based on the data provider's preferences). You will need to supply the configuration, which will be processed and executed by the Airbyte platform on your behalf (self-managed configuration).
+
+
+## Declarative OAuth 2.0
+
+Declarative OAuth is a powerful feature that allows connector developers to implement OAuth authentication flows without writing any code. Instead of implementing custom OAuth logic, developers can describe their OAuth flow through configuration in their connector's spec file.
+
+**Key Benefits:**
+* **Zero Code Implementation** - Define your entire OAuth flow through configuration
+* **Flexible & Customizable** - Handles both standard and non-standard OAuth implementations through custom parameters, headers, and URL templates
+* **Standardized & Secure** - Uses Airbyte's battle-tested OAuth implementation
+* **Maintainable** - OAuth configuration lives in one place and is easy to update
+
+**When to Use:**
+* You need to implement OAuth authentication for a new connector
+* Your API uses standard OR custom OAuth 2.0 flows
+* You want to refactor an existing custom OAuth implementation
+* You need to customize OAuth parameters, headers, or URL structures
+
+**How it Works:**
+1. Developer defines OAuth configuration in connector spec
+2. Airbyte handles OAuth flow coordination:
+ * Generating consent URLs
+ * Managing state parameters
+ * Token exchange
+ * Refresh token management
+ * Custom parameter injection
+ * Header management
+3. Connector receives valid tokens for API authentication
+
+The feature is configured through the `advanced_auth.oauth_config_specification` field in your connector's spec file, with most of the OAuth-specific configuration happening in the `oauth_connector_input_specification` subfield.
+
+### Overview
+
+In an ideal world, implementing OAuth 2.0 authentication for each data provider would be straightforward. The main pattern involves: `Consent Screen` > `Permission/Scopes Validation` > `Access Granted`. At Airbyte, we've refined various techniques to provide the best OAuth 2.0 experience for community developers.
+
+Previously, each connector supporting OAuth 2.0 required a custom implementation, which was difficult to maintain, involved extensive testing, and was prone to issues when introducing breaking changes.
+
+The modern solution is the `DeclarativeOAuthFlow`, which allows customers to configure, test, and maintain OAuth 2.0 using `JSON` or `YAML` configurations instead of extensive code.
+
+Once the configuration is set, the `DeclarativeOAuthFlow` handles the following steps:
+- Formats pre-defined URLs (including variable resolution)
+- Displays the `Consent Screen` for permission/scope verification (depending on the data provider)
+- Completes the flow by granting the `access_token`/`refresh_token` for authenticated API calls
+
+### Implementation Examples
+
+Let's walk through implementing OAuth flows of increasing complexity. Each example builds on the previous one.
+
+**Base Connector Spec**
+Here is an example of a manifest for a connector that
+1. Has no existing Auth
+2. Connects to the Pokemon API
+3. Pulls data from the moves stream
+
+
+ Example Base Connector Spec
+
+```yaml
+version: 6.13.0
+
+type: DeclarativeSource
+
+check:
+ type: CheckStream
+ stream_names:
+ - moves
+
+definitions:
+ streams:
+ moves:
+ type: DeclarativeStream
+ name: moves
+ retriever:
+ type: SimpleRetriever
+ requester:
+ $ref: "#/definitions/base_requester"
+ path: /api/v2/move/
+ http_method: GET
+ record_selector:
+ type: RecordSelector
+ extractor:
+ type: DpathExtractor
+ field_path: []
+ paginator:
+ type: DefaultPaginator
+ page_token_option:
+ type: RequestPath
+ pagination_strategy:
+ type: CursorPagination
+ cursor_value: "{{ response.get('next') }}"
+ stop_condition: "{{ response.get('next') is none }}"
+ schema_loader:
+ type: InlineSchemaLoader
+ schema:
+ $ref: "#/schemas/moves"
+ base_requester:
+ type: HttpRequester
+ url_base: https://pokeapi.co
+
+streams:
+ - $ref: "#/definitions/streams/moves"
+
+spec:
+ type: Spec
+ connection_specification:
+ type: object
+ $schema: http://json-schema.org/draft-07/schema#
+ required: []
+ properties: {}
+ additionalProperties: true
+
+schemas:
+ moves:
+ type: object
+ $schema: http://json-schema.org/schema#
+ additionalProperties: true
+ properties:
+ count:
+ type:
+ - number
+ - "null"
+ next:
+ type:
+ - string
+ - "null"
+ previous:
+ type:
+ - string
+ - "null"
+ results:
+ type:
+ - array
+ - "null"
+ items:
+ type:
+ - object
+ - "null"
+ properties:
+ name:
+ type:
+ - string
+ - "null"
+ url:
+ type:
+ - string
+ - "null"
+```
+
+
+
+#### Basic OAuth Flow
+Lets update the spec to add a very basic OAuth flow with
+1. No custom parameters
+2. No custom headers
+3. No custom query parameters
+4. No refresh token support
+5. No overrides to existing keys
+6. No overrides to where we store or extract access tokens from
+7. No overrides to where we store or extract client ids and secrets from
+
+This service has two endpoints:
+**Consent URL**
+`/oauth/consent` - This is the consent URL that the user will be redirected to in order to authorize the connector
+
+Example: `https://yourconnectorservice.com/oauth/consent?client_id=YOUR_CLIENT_ID_123&redirect_uri=https://cloud.airbyte.com&state=some_random_state_string`
+
+**Token URL**
+`/oauth/token` - This is the token URL that the connector will use to exchange the code for an access token
+
+Example URL:
+`https://yourconnectorservice.com/oauth/token?client_id=YOUR_CLIENT_ID_123&client_secret=YOUR_CLIENT_SECRET_123&code=some_random_code_string`
+
+
+ Example Response
+
+ ```json
+ {
+ "access_token": "YOUR_ACCESS_TOKEN_123"
+ }
+ ```
+
+
+
+ Example Declarative OAuth Spec
+
+ ```diff
+--- manifest.yml
++++ simple_oauth_manifest.yml
+definitions:
+ base_requester:
+ type: HttpRequester
+ url_base: https://pokeapi.co
++ authenticator:
++ type: OAuthAuthenticator
++ refresh_request_body: {}
++ client_id: "{{ config[\"client_id\"] }}"
++ client_secret: "{{ config[\"client_secret\"] }}"
++ access_token_value: "{{ config[\"client_access_token\"] }}"
+
+spec:
+ connection_specification:
+ type: object
+ $schema: http://json-schema.org/draft-07/schema#
+- required: []
+- properties: {}
++ required:
++ - client_id
++ - client_secret
++ - client_access_token
++ properties:
++ client_id:
++ type: string
++ client_secret:
++ type: string
++ client_access_token:
++ type: string
++ airbyte_secret: true
+ additionalProperties: true
++ advanced_auth:
++ auth_flow_type: oauth2.0
++ oauth_config_specification:
++ oauth_connector_input_specification:
++ consent_url: >-
++ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
++ redirect_uri_value}}&state={{state}}
++ access_token_url: >-
++ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code {{auth_code_value}}
++ complete_oauth_output_specification:
++ required:
++ - access_token
++ properties:
++ access_token:
++ type: string
++ path_in_connector_config:
++ - access_token
++ path_in_oauth_response:
++ - access_token
++ complete_oauth_server_input_specification:
++ required:
++ - client_id
++ - client_secret
++ properties:
++ client_id:
++ type: string
++ client_secret:
++ type: string
++ complete_oauth_server_output_specification:
++ required:
++ - client_id
++ - client_secret
++ properties:
++ client_id:
++ type: string
++ path_in_connector_config:
++ - client_id
++ client_secret:
++ type: string
++ path_in_connector_config:
++ - client_secret
+```
+
+
+#### Advanced Case: client secret is a request header not a query parameter
+Imagine that the OAuth flow is updated so that the client secret is a request header instead of a query parameter.
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- simple_oauth_manifest.yml
++++ secret_header_manifest.yml
+ spec:
+ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+ redirect_uri_value }}&state={{ state }}
+ access_token_url: >-
+- https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
++ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&code={{auth_code_value}}
++ access_token_headers:
++ SECRETHEADER: "{{ client_secret_value }}"
+ complete_oauth_output_specification:
+ required:
+```
+
+
+
+ Example with the header value encoded into `base64-string`
+
+```diff
+--- secret_header_manifest.yml
++++ secret_header_manifest.yml
+ spec:
+ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+ redirect_uri_value }}&state={{ state }}
+ access_token_url: >-
+- https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
++ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&code={{auth_code_value}}
++ access_token_headers:
+- SECRETHEADER: "{{ client_secret_value }}"
++ SECRETHEADER: "{{ {{client_id_value}}:{{client_secret_value}} | base64Encoder }}"
+ complete_oauth_output_specification:
+ required:
+```
+
+
+
+#### Advanced Case: access token url query parameters should be `JSON-encoded`
+Imagine that the OAuth flow is updated so that the query parameters should be `JSON-encoded` to obtain the `access_token/refresh_token`, during the `code` to `access_token/refresh_token` exchange. In this case the `access_token_url` should not include the variables as a part of the `url` itself. Use the `access_token_params` property to include the `JSON-encoded` params in the `body` of the request.
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- simple_oauth_manifest.yml
++++ secret_header_manifest.yml
+ spec:
+ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+ redirect_uri_value }}&state={{ state }}
+ access_token_url: >-
+- https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
++ https://yourconnectorservice.com/oauth/token
++ access_token_params:
++ client_id: "{{ client_id_value }}"
++ client_secret: "{{ client_secret_value }}"
++ redirect_uri: "{{ redirect_uri_value }}"
+ complete_oauth_output_specification:
+ required:
+```
+
+
+The underlying `JSON-encoded` parameters will be included in the `body` of the outgoing request, instead of being a part of the `access_token_url` url value, as follows:
+
+
+ Example rendered `access_token_params`
+
+```json
+{
+ "client_id": "YOUR_CLIENT_ID_123",
+ "client_secret": "YOUR_CLIENT_SECRET_123",
+ "redirect_uri": "https://cloud.airbyte.com",
+}
+```
+
+
+
+#### Advanced Case: access token is returned in a non standard / nested field
+Now imagine that the OAuth flow is updated so that the access token returned by `/oauth/token` is in a nested non standard field. Specifically, the response is now:
+
+
+ Example response
+
+```json
+{
+ "data": {
+ "super_duper_access_token": "YOUR_ACCESS_TOKEN_123"
+ }
+}
+```
+
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ different_access_token_field.yml
+ spec:
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
+ complete_oauth_output_specification:
+ required:
+- - access_token
++ - super_duper_access_token
+ properties:
+- access_token:
++ super_duper_access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
++ path_in_oauth_response:
++ - data
++ - super_duper_access_token
+ complete_oauth_server_input_specification:
+```
+
+
+#### Advanced Case: refresh token / single-use refresh token support
+Imagine that the OAuth flow is updated so that the OAuth flow now supports refresh tokens.
+
+Meaning that the OAuth flow now has an additional endpoint:
+`/oauth/refresh` - This is the refresh token URL that the connector will use to exchange the refresh token for an access token
+
+
+ Example URL
+
+`https://yourconnectorservice.com/oauth/refresh/endpoint`
+
+
+and the response of `/oauth/token` now includes a refresh token field.
+
+
+ Example response
+
+```json
+{
+ "access_token": "YOUR_ACCESS_TOKEN_123",
+ "refresh_token": "YOUR_REFRESH_TOKEN_123",
+ "expires_in": 7200,
+}
+```
+
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ refresh_token.yml
+ definitions:
+ authenticator:
+ type: OAuthAuthenticator
+ refresh_request_body: {}
++ grant_type: refresh_token
+ client_id: "{{ config[\"client_id\"] }}"
+ client_secret: "{{ config[\"client_secret\"] }}"
++ refresh_token: "{{ config[\"client_refresh_token\"] }}"
+ access_token_value: "{{ config[\"client_access_token\"] }}"
++ access_token_name: access_token
++ refresh_token_updater:
++ refresh_token_name: refresh_token
++ refresh_token_config_path:
++ - client_refresh_token
++ token_refresh_endpoint: >-
++ https://yourconnectorservice.com/oauth/refresh/endpoint
+
+ streams:
+ - $ref: "#/definitions/streams/moves"
+ spec:
+ required:
+ - client_id
+ - client_secret
+- - client_access_token
++ - client_refresh_token
+ properties:
+ client_id:
+ type: string
+@@ -68,9 +77,9 @@ spec:
+- client_access_token:
++ client_refresh_token:
+ type: string
+- title: Access token
++ title: Refresh token
+@@ -86,16 +95,22 @@ spec:
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
++ - refresh_token
++ - token_expiry_date
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
++ path_in_oauth_response:
++ - access_token
++ refresh_token:
++ type: string
++ path_in_connector_config:
++ - refresh_token
++ path_in_oauth_response:
++ - refresh_token
++ token_expiry_date:
++ type: string
++ path_in_connector_config:
++ - token_expiry_date
++ path_in_oauth_response:
++ - expires_in
+ complete_oauth_server_input_specification:
+ required:
+ - client_id
+```
+
+
+#### Advanced Case: scopes should be provided as a query parameter
+Imagine that the OAuth flow is updated so that you need to mention the `scope` query parameter to get to the `consent screen` and verify / grant the access to the neccessary onces, before moving forward.
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ scopes.yml
+@@ -80,10 +80,10 @@ spec:
+ oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+- https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+- redirect_uri_value }}&state={{ state_value }}
++ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{ redirect_uri_value }}&state={{ state_value }}&scope={{scope_value}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
++ scope: my_scope_A:read,my_scope_B:read
+ complete_oauth_output_specification:
+ required:
+ - access_token
+```
+
+
+#### Advanced Case: generate the complex `state` value and make it a part of the query parameter
+Imagine that the OAuth flow is updated so that you need to mention the `state` query parameter being generated with the minimum `10` and maximum `27` symbols.
+
+
+ Example URL
+
+`https://yourconnectorservice.com/oauth/consent?client_id=YOUR_CLIENT_ID_123&redirect_uri=https://cloud.airbyte.com&state=2LtdNpN8pmkYOBDqoVR3NzYQ`
+
+
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ base_oauth_with_custom_state.yml
+@@ -80,10 +80,10 @@ spec:
+ oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+ redirect_uri_value }}&state={{ state_value }}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
++ state: {
++ min: 10,
++ max: 27
++ }
+ complete_oauth_output_specification:
+ required:
+ - access_token
+```
+
+
+
+##### Example using an url-encoded / url-decoded `scope` parameter
+You can make the `scope` paramter `url-encoded` by specifying the `pipe` ( | ) + `urlEncoder` or `urlDecoder` in the target url.
+It would be pre-formatted and resolved into the `url-encoded` string before being replaced for the final resolved URL.
+
+
+ Example URL
+
+`https://yourconnectorservice.com/oauth/consent?client_id=YOUR_CLIENT_ID_123&redirect_uri=https://cloud.airbyte.com&state=some_random_state_string&scope=my_scope_A%3Aread%20my_scope_B%3Aread`
+
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- scopes.yml
++++ scopes.yml
+@@ -80,10 +80,10 @@ spec:
+ oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+- https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+- redirect_uri_value }}&state={{ state_value }}&scope={{scope_value}}
++ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{ redirect_uri_value }}&state={{ state_value }}&scope={{ {{scope_value}} | urlEncoder }}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
+- scope: my_scope_A:read,my_scope_B:read
++ scope: my_scope_A:read my_scope_B:read
+ complete_oauth_output_specification:
+ required:
+ - access_token
+```
+
+
+
+#### Advanced Case: get code challenge from the `state_value` and set as a part of the `consent_url`
+Imagine that the OAuth flow is updated so that you need to generate the `code challenge`, using `SHA-256` hash and include this as a query parameter in the `consent_url` to get to the `Consent Screen`, before moving forward with authentication.
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ base_oauth.yml
+ spec:
+ oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+- https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+- redirect_uri_value }}&state={{ state_value }}
++ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
++ redirect_uri_value }}&state={{ state_value }}&code_challenge={{ {{state_value}} | codeChallengeS256 }}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_code_value}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+```
+
+
+#### Advanced Case: The Connector is already using Legacy OAuth and the credentials are stored in a strange place
+Imagine that the connector is already using Legacy OAuth and the credentials are stored in a strange place.
+
+Specifically:
+1. `client_id` is located in a users config file at `airbyte.super_secret_credentials.pokemon_client_id`
+2. `client_secret` is located in a users config file at `airbyte.super_secret_credentials.pokemon_client_secret`
+3. `access_token` is located in a users config file at `airbyte.super_secret_credentials.pokemon_access_token`
+
+and we need to make sure that updating the spec to use Declarative OAuth doesn't break existing syncs.
+
+
+ Example Declarative OAuth Change
+
+```diff
+--- base_oauth.yml
++++ legacy_to_declarative_oauth.yml
+ definitions:
+ authenticator:
+ type: OAuthAuthenticator
+ refresh_request_body: {}
+- client_id: '{{ config["client_id"] }}'
+- client_secret: '{{ config["client_secret"] }}'
+- access_token_value: '{{ config["client_access_token"] }}'
++ client_id: '{{ config["super_secret_credentials"]["pokemon_client_id"] }}'
++ client_secret: '{{ config["super_secret_credentials"]["pokemon_client_secret"] }}'
++ access_token_value: '{{ config["super_secret_credentials"]["pokemon_access_token"] }}'
+
+ streams:
+ - $ref: "#/definitions/streams/moves"
+ spec:
+ type: object
+ $schema: http://json-schema.org/draft-07/schema#
+ required:
+- - client_id
+- - client_secret
+- - client_access_token
++ - super_secret_credentials
+ properties:
+- client_id:
+- type: string
+- title: Client ID
+- airbyte_secret: true
+- order: 0
+- client_secret:
+- type: string
+- title: Client secret
+- airbyte_secret: true
+- order: 1
+- client_access_token:
+- type: string
+- title: Access token
+- airbyte_secret: true
+- airbyte_hidden: false
+- order: 2
++ super_secret_credentials:
++ required:
++ - pokemon_client_id
++ - pokemon_client_secret
++ - pokemon_access_token
++ pokemon_client_id:
++ type: string
++ title: Client ID
++ airbyte_secret: true
++ order: 0
++ pokemon_client_secret:
++ type: string
++ title: Client secret
++ airbyte_secret: true
++ order: 1
++ pokemon_access_token:
++ type: string
++ title: Access token
++ airbyte_secret: true
++ airbyte_hidden: false
++ order: 2
+ additionalProperties: true
+ advanced_auth:
+ auth_flow_type: oauth2.0
+ oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+- https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{
+- redirect_uri_value }}&state={{ state_value }}
++ https://yourconnectorservice.com/oauth/consent?client_id={{client_id_value}}&redirect_uri={{ redirect_uri_value }}&state={{ s
+tate_value }}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?client_id={{client_id_value}}&client_secret={{client_secret_value}}&code={{auth_
+code_value}}
++ client_id_key: pokemon_client_id
++ client_secret_key: pokemon_client_secret
+ complete_oauth_output_specification:
+ required:
+- - access_token
++ - pokemon_access_token
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+- - access_token
++ - super_secret_credentials
++ - pokemon_access_token
+ path_in_oauth_response:
+ - access_token
+ complete_oauth_server_input_specification:
+ required:
+- - client_id
+- - client_secret
++ - pokemon_client_id
++ - pokemon_client_secret
+ properties:
+- client_id:
++ pokemon_client_id:
+ type: string
+- client_secret:
++ pokemon_client_secret:
+ type: string
+ complete_oauth_server_output_specification:
+ required:
+- - client_id
+- - client_secret
++ - pokemon_client_id
++ - pokemon_client_secret
+ properties:
+- client_id:
++ pokemon_client_id:
+ type: string
+ path_in_connector_config:
+- - client_id
+- client_secret:
++ - super_secret_credentials
++ - pokemon_client_id
++ pokemon_client_secret:
+ type: string
+ path_in_connector_config:
+- - client_secret
++ - super_secret_credentials
++ - pokemon_client_secret
+
+```
+
+
+### Configuration Fields
+
+#### Required Fields
+
+| Field | Description | Default Value |
+|-------|-------------|---------------|
+| `consent_url` | The URL where the user will be redirected to authorize the connector | |
+| `access_token_url` | The URL where the connector will exchange the authorization code for an access token | |
+
+
+#### Optional Fields
+
+| Field | Description | Default Value |
+|-------|-------------|---------------|
+| `access_token_headers` | The optional headers to inject while exchanging the `auth_code` to `access_token` | |
+| `access_token_params` | The optional query parameters to inject while exchanging the `auth_code` to `access_token` | |
+| `auth_code_key` | The optional override to provide the custom `code` key name to something like `auth_code` or `custom_auth_code`, if required by data-provider | "code" |
+| `client_id_key` | The optional override to provide the custom `client_id` key name, if required by data-provider | "client_id" |
+| `client_secret_key` | The optional override to provide the custom `client_secret` key name, if required by data-provider | "client_secret" |
+| `redirect_uri_key` | The optional override to provide the custom `redirect_uri` key name to something like `callback_uri`, if required by data-provider | "redirect_uri" |
+| `scope` | The optional string of the scopes needed to be grant for authenticated user, should be pre-defined as a `string` in a format that is expected by the data-provider | |
+| `scope_key` | The optional override to provide the custom `scope` key name, if required by data-provider | "scope" |
+| `state` | The object to provide the criteria of how the `state` query param should be constructed, including length and complexity | |
+| `state_key` | The optional override to provide the custom `state` key name, if required by data-provider | "state" |
+| `token_expiry_key` | The optional override to provide the custom key name to something like `expires_at`, if required by data-provider | "expires_in" |
+
+### Available Template Variables
+| Variable | Description | Default Value |
+|----------|-------------|---------------|
+| `{{ client_id_key }}` | The key used to identify the client ID in request bodies | "client_id" |
+| `{{ client_id_value }}` | The client ID value retrieved from the config location specified by client_id_key | Value from config[client_id_key] |
+| `{{ client_id_param }}` | The parameter name and value pair used for the client ID in URLs | "client_id=client id value here" |
+| `{{ client_secret_key }}` | The key used to identify the client secret in request bodies | "client_secret" |
+| `{{ client_secret_value }}` | The client secret value retrieved from the config location specified by client_secret_key | Value from config[client_secret_key] |
+| `{{ client_secret_param }}` | The parameter name and value pair used for the client secret in URLs | "client_secret=client secret value here" |
+| `{{ redirect_uri_key }}` | The key used to identify the redirect URI in request bodies | "redirect_uri" |
+| `{{ redirect_uri_value }}` | The redirect URI value used for OAuth callbacks | This value is set based on your deployment and handled by Airbyte |
+| `{{ redirect_uri_param }}` | The parameter name and value pair used for the redirect URI in URLs | "redirect_uri=redirect uri value here" |
+| `{{ scope_key }}` | The key used to identify the scope in request bodies | "scope" |
+| `{{ scope_value }}` | The scope value specifying the access permissions being requested | Value from config[scope_key] |
+| `{{ scope_param }}` | The parameter name and value pair used for the scope in URLs | "scope=scope value here" |
+| `{{ state_key }}` | The key used to identify the state parameter in request bodies | "state" |
+| `{{ state_value }}` | A random string used to prevent CSRF attacks | Randomly generated string |
+| `{{ state_param }}` | The parameter name and value pair used for the state in URLs | "state=state value here" |
+| `{{ auth_code_key }}` | The key used to identify the authorization code in request bodies | "code" |
+| `{{ auth_code_value }}` | The authorization code received from the OAuth provider | Value from OAuth callback |
+| `{{ auth_code_param }}` | The parameter name and value pair used for the auth code in URLs | "code=auth code value here" |
+
+### Available Template Variables PIPE methods
+
+You can apply the `in-vatiable` tranformations based on your use-case and use the following interpolation methods available:
+
+| Method | Description | Input Value | Output Value |
+|----------|-------------|------|------|
+| `base64Encoder` | The variable method to encode the input string into `base64-encoded` string | "client_id_123:client_secret_456" | "Y2xpZW50X2lkXzEyMzpjbGllbnRfc2VjcmV0XzQ1Ng" |
+| `base64Encoder` | The variable method to decode the `base64-encoded` input string into `base64-decoded` string | "Y2xpZW50X2lkXzEyMzpjbGllbnRfc2VjcmV0XzQ1Ng" | "client_id_123:client_secret_456" |
+| `codeChallengeS256` | The variable method to encode the input string into `SHA-256` hashed-string | "id_123:secret_456" | "kdlBQTTftIOzHnzQoqp3dQ5jBsSehFTjg1meg1gL3OY" |
+| `urlEncoder` | The variable method to encode the input string as `URL-string` | "my string input" | "my%20string%20input" |
+| `urlDecoder` | The variable method to decode the input `URL-string` into decoded string | "my%20string%20input" | "my string input" |
+
+
+### Common Use-Cases and Examples:
+The following section stands to describe common use-cases. Assuming that there are no overides provided over the `default` keys, the common specification parts (properties) like: `complete_oauth_server_input_specification` and `complete_oauth_server_output_specification` remain unchanged
+
+
+ Example Common Advanced Auth parts
+
+```yaml
+complete_oauth_server_input_specification:
+ required:
+ - client_id
+ - client_secret
+ properties:
+ client_id:
+ type: string
+ client_secret:
+ type: string
+complete_oauth_server_output_specification:
+ required:
+ - client_id
+ - client_secret
+ properties:
+ client_id:
+ type: string
+ path_in_connector_config:
+ - client_id
+ client_secret:
+ type: string
+ path_in_connector_config:
+ - client_secret
+```
+
+
+#### Case A: OAuth Flow returns the `access_token` only
+When the `access_token` is the only key expected after the successfull `OAuth2.0` authentication
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
+ path_in_oauth_response:
+ - access_token
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "access_token": "YOUR_ACCESS_TOKEN_123"
+}
+```
+
+
+##### Case A-1: OAuth Flow returns the nested `access_token` only, under the `data` property
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
+ path_in_oauth_response:
+ - data
+ - access_token
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "data": {
+ "access_token": "YOUR_ACCESS_TOKEN_123"
+ }
+}
+```
+
+
+
+#### Case B: OAuth Flow returns the `refresh_token` only
+When the `refresh_token` is the only key expected after the successfull `OAuth2.0` authentication
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - refresh_token
+ properties:
+ refresh_token:
+ type: string
+ path_in_connector_config:
+ - refresh_token
+ path_in_oauth_response:
+ - refresh_token
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "refresh_token": "YOUR_ACCESS_TOKEN_123"
+}
+```
+
+
+#### Case C: OAuth Flow returns the `access_token` and the `refresh_token`
+When the the `access_token` and the `refresh_token` are the only keys expected after the successfull `OAuth2.0` authentication
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+ - refresh_token
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
+ path_in_oauth_response:
+ - access_token
+ refresh_token:
+ type: string
+ path_in_connector_config:
+ - refresh_token
+ path_in_oauth_response:
+ - refresh_token
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "access_token": "YOUR_ACCESS_TOKEN_123",
+ "refresh_token": "YOUR_REFRESH_TOKEN_123"
+}
+```
+
+
+##### Case C-1: OAuth Flow returns the `access_token` and the `refresh_token` nested under the `data` property and each key is nested inside the dedicated placeholder
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+ - refresh_token
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
+ path_in_oauth_response:
+ - data
+ - access_token_placeholder
+ - access_token
+ refresh_token:
+ type: string
+ path_in_connector_config:
+ - refresh_token
+ path_in_oauth_response:
+ - data
+ - refresh_token_placeholder
+ - refresh_token
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "data": {
+ "access_token_placeholder": {
+ "access_token": "YOUR_ACCESS_TOKEN_123"
+ },
+ "refresh_token_placeholder" {
+ "refresh_token": "YOUR_REFRESH_TOKEN_123"
+ }
+ }
+}
+```
+
+
+#### Case D: OAuth Flow returns the `access_token` and the `refresh_token` is a `one-time-usage` key
+In this example we expect the `refresh_token` key expires alongside with the `access_token` and should be exhanged altogether, having the new pair of keys in response. The `token_expiry_date` is the property that holds the `date-time` value of when the `access_token` should be expired
+
+
+ Example Declarative OAuth Specification
+
+```yaml
+# advanced_auth
+
+oauth_config_specification:
+ oauth_connector_input_specification:
+ consent_url: >-
+ https://yourconnectorservice.com/oauth/consent?{{client_id_param}}&{{redirect_uri_param}}&{{state_param}}
+ access_token_url: >-
+ https://yourconnectorservice.com/oauth/token?{{client_id_param}}&{{client_secret_param}}&{{auth_code_param}}
+ complete_oauth_output_specification:
+ required:
+ - access_token
+ - refresh_token
+ - token_expiry_date
+ properties:
+ access_token:
+ type: string
+ path_in_connector_config:
+ - access_token
+ path_in_oauth_response:
+ - access_token
+ refresh_token:
+ type: string
+ path_in_connector_config:
+ - refresh_token
+ path_in_oauth_response:
+ - refresh_token
+ token_expiry_date:
+ type: string
+ path_in_connector_config:
+ - token_expiry_date
+ path_in_oauth_response:
+ - expires_in
+
+ # Other common properties are omitted, see the `More common use-cases` description
+```
+
+
+
+ Example `path_in_oauth_response`
+
+```json
+{
+ "access_token": "YOUR_ACCESS_TOKEN_123",
+ "refresh_token": "YOUR_REFRESH_TOKEN_123",
+ "expires_in": 7200
+}
+```
+
+
+
+## Partial OAuth (legacy)
+
+The partial OAuth flow is a simpler flow that allows you to use an existing access (or refresh) token to authenticate with the API.
+
+The catch is that the user needs to implement the start of the OAuth flow manually to obtain the `access_token` and the `refresh_token` and pass them to the connector as a part of the `config` object.
+
+This method is supported through the `OAuthAuthenticator`, which requires the following parameters:
+
+- `token_refresh_endpoint`: The endpoint to refresh the access token
+- `client_id`: The client id
+- `client_secret`: The client secret
+- `refresh_token`: The token used to refresh the access token
+- `scopes` (Optional): The scopes to request. Default: Empty list
+- `token_expiry_date` (Optional): The access token expiration date formatted as RFC-3339 ("%Y-%m-%dT%H:%M:%S.%f%z")
+- `access_token_name` (Optional): The field to extract access token from in the response. Default: "access_token".
+- `expires_in_name` (Optional): The field to extract expires_in from in the response. Default: "expires_in"
+- `refresh_request_body` (Optional): The request body to send in the refresh request. Default: None
+- `grant_type` (Optional): The parameter specified grant_type to request access_token. Default: "refresh_token"
+
+
+ Example Schema
+
+```yaml
+OAuth:
+ type: object
+ additionalProperties: true
+ required:
+ - token_refresh_endpoint
+ - client_id
+ - client_secret
+ - refresh_token
+ - access_token_name
+ - expires_in_name
+ properties:
+ "$parameters":
+ "$ref": "#/definitions/$parameters"
+ token_refresh_endpoint:
+ type: string
+ client_id:
+ type: string
+ client_secret:
+ type: string
+ refresh_token:
+ type: string
+ scopes:
+ type: array
+ items:
+ type: string
+ default: []
+ token_expiry_date:
+ type: string
+ access_token_name:
+ type: string
+ default: "access_token"
+ expires_in_name:
+ type: string
+ default: "expires_in"
+ refresh_request_body:
+ type: object
+ grant_type:
+ type: string
+ default: "refresh_token"
+ refresh_token_updater:
+ title: Token Updater
+ description: When the token updater is defined, new refresh tokens, access tokens and the access token expiry date are written back from the authentication response to the config object. This is important if the refresh token can only used once.
+ properties:
+ refresh_token_name:
+ title: Refresh Token Property Name
+ description: The name of the property which contains the updated refresh token in the response from the token refresh endpoint.
+ type: string
+ default: "refresh_token"
+ access_token_config_path:
+ title: Config Path To Access Token
+ description: Config path to the access token. Make sure the field actually exists in the config.
+ type: array
+ items:
+ type: string
+ default: ["credentials", "access_token"]
+ refresh_token_config_path:
+ title: Config Path To Refresh Token
+ description: Config path to the access token. Make sure the field actually exists in the config.
+ type: array
+ items:
+ type: string
+ default: ["credentials", "refresh_token"]
+```
+
+
+
+ Example Authenticator
+
+```yaml
+authenticator:
+ type: "OAuthAuthenticator"
+ token_refresh_endpoint: "https://api.searchmetrics.com/v4/token"
+ client_id: "{{ config['api_key'] }}"
+ client_secret: "{{ config['client_secret'] }}"
+ refresh_token: ""
+```
+
+
+For more information see [OAuthAuthenticator Reference](https://docs.airbyte.com/connector-development/config-based/understanding-the-yaml-file/reference#/definitions/OAuthAuthenticator)
diff --git a/docs/connector-development/config-based/advanced-topics/object-instantiation.md b/docs/connector-development/config-based/advanced-topics/object-instantiation.md
new file mode 100644
index 0000000000000..19f9ab732e37f
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/object-instantiation.md
@@ -0,0 +1,46 @@
+# Object Instantiation
+
+If the component is a literal, then it is returned as is:
+
+```
+3
+```
+
+will result in
+
+```
+3
+```
+
+If the component definition is a mapping with a "type" field,
+the factory will lookup the [CLASS_TYPES_REGISTRY](https://github.com/airbytehq/airbyte-python-cdk/blob/main//airbyte_cdk/sources/declarative/parsers/class_types_registry.py) and replace the "type" field by "class_name" -> CLASS_TYPES_REGISTRY[type]
+and instantiate the object from the resulting mapping
+
+If the component definition is a mapping with neither a "class_name" nor a "type" field,
+the factory will do a best-effort attempt at inferring the component type by looking up the parent object's constructor type hints.
+If the type hint is an interface present in [DEFAULT_IMPLEMENTATIONS_REGISTRY](https://github.com/airbytehq/airbyte-python-cdk/blob/main//airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py),
+then the factory will create an object of its default implementation.
+
+If the component definition is a list, then the factory will iterate over the elements of the list,
+instantiate its subcomponents, and return a list of instantiated objects.
+
+If the component has subcomponents, the factory will create the subcomponents before instantiating the top level object
+
+```
+{
+ "type": TopLevel
+ "param":
+ {
+ "type": "ParamType"
+ "k": "v"
+ }
+}
+```
+
+will result in
+
+```
+TopLevel(param=ParamType(k="v"))
+```
+
+More details on object instantiation can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=factory#airbyte_cdk.sources.declarative.parsers.factory.DeclarativeComponentFactory).
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/parameters.md b/docs/connector-development/config-based/advanced-topics/parameters.md
new file mode 100644
index 0000000000000..38ab811974982
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/parameters.md
@@ -0,0 +1,50 @@
+# Parameters
+
+Parameters can be passed down from a parent component to its subcomponents using the $parameters key.
+This can be used to avoid repetitions.
+
+Schema:
+
+```yaml
+"$parameters":
+ type: object
+ additionalProperties: true
+```
+
+Example:
+
+```yaml
+outer:
+ $parameters:
+ MyKey: MyValue
+ inner:
+ k2: v2
+```
+
+This the example above, if both outer and inner are types with a "MyKey" field, both of them will evaluate to "MyValue".
+
+These parameters can be overwritten by subcomponents as a form of specialization:
+
+```yaml
+outer:
+ $parameters:
+ MyKey: MyValue
+ inner:
+ $parameters:
+ MyKey: YourValue
+ k2: v2
+```
+
+In this example, "outer.MyKey" will evaluate to "MyValue", and "inner.MyKey" will evaluate to "YourValue".
+
+The value can also be used for string interpolation:
+
+```yaml
+outer:
+ $parameters:
+ MyKey: MyValue
+ inner:
+ k2: "MyKey is {{ parameters['MyKey'] }}"
+```
+
+In this example, outer.inner.k2 will evaluate to "MyKey is MyValue"
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/references.md b/docs/connector-development/config-based/advanced-topics/references.md
new file mode 100644
index 0000000000000..b4f71ca78c971
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/references.md
@@ -0,0 +1,102 @@
+# References
+
+Strings can contain references to previously defined values.
+The parser will dereference these values to produce a complete object definition.
+
+References can be defined using a `#/{arg}` string.
+
+```yaml
+key: 1234
+reference: "#/key"
+```
+
+will produce the following definition:
+
+```yaml
+key: 1234
+reference: 1234
+```
+
+This also works with objects:
+
+```yaml
+key_value_pairs:
+ k1: v1
+ k2: v2
+same_key_value_pairs: "#/key_value_pairs"
+```
+
+will produce the following definition:
+
+```yaml
+key_value_pairs:
+ k1: v1
+ k2: v2
+same_key_value_pairs:
+ k1: v1
+ k2: v2
+```
+
+The $ref keyword can be used to refer to an object and enhance it with addition key-value pairs
+
+```yaml
+key_value_pairs:
+ k1: v1
+ k2: v2
+same_key_value_pairs:
+ $ref: "#/key_value_pairs"
+ k3: v3
+```
+
+will produce the following definition:
+
+```yaml
+key_value_pairs:
+ k1: v1
+ k2: v2
+same_key_value_pairs:
+ k1: v1
+ k2: v2
+ k3: v3
+```
+
+References can also point to nested values.
+Nested references are ambiguous because one could define a key containing with `/`
+in this example, we want to refer to the limit key in the dict object:
+
+```yaml
+dict:
+ limit: 50
+limit_ref: "#/dict/limit"
+```
+
+will produce the following definition:
+
+```yaml
+dict
+limit: 50
+limit-ref: 50
+```
+
+whereas here we want to access the `nested/path` value.
+
+```yaml
+nested:
+ path: "first one"
+nested.path: "uh oh"
+value: "ref(nested.path)
+```
+
+will produce the following definition:
+
+```yaml
+nested:
+ path: "first one"
+nested/path: "uh oh"
+value: "uh oh"
+```
+
+To resolve the ambiguity, we try looking for the reference key at the top-level, and then traverse the structs downward
+until we find a key with the given path, or until there is nothing to traverse.
+
+More details on referencing values can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=yamlparser#airbyte_cdk.sources.declarative.parsers.yaml_parser.YamlParser).
\ No newline at end of file
diff --git a/docs/connector-development/config-based/advanced-topics/string-interpolation.md b/docs/connector-development/config-based/advanced-topics/string-interpolation.md
new file mode 100644
index 0000000000000..2726b0cb4b295
--- /dev/null
+++ b/docs/connector-development/config-based/advanced-topics/string-interpolation.md
@@ -0,0 +1,36 @@
+# String Interpolation
+
+String values can be evaluated as Jinja2 templates.
+
+If the input string is a raw string, the interpolated string will be the same.
+`"hello world" -> "hello world"`
+
+The engine will evaluate the content passed within `{{...}}`, interpolating the keys from context-specific arguments.
+The "parameters" keyword [see ($parameters)](./parameters.md) can be referenced.
+
+For example, some_object.inner_object.key will evaluate to "Hello airbyte" at runtime.
+
+```yaml
+some_object:
+ $parameters:
+ name: "airbyte"
+ inner_object:
+ key: "Hello {{ parameters.name }}"
+```
+
+Some components also pass in additional arguments to the context.
+This is the case for the [record selector](../understanding-the-yaml-file/record-selector.md), which passes in an additional `response` argument.
+
+Both dot notation and bracket notations (with single quotes ( `'`)) are interchangeable.
+This means that both these string templates will evaluate to the same string:
+
+1. `"{{ parameters.name }}"`
+2. `"{{ parameters['name'] }}"`
+
+In addition to passing additional values through the $parameters argument, macros can be called from within the string interpolation.
+For example,
+`"{{ max(2, 3) }}" -> 3`
+
+The macros and variables available in all possible contexts are documented in the [YAML Reference](../understanding-the-yaml-file/reference.md#variables).
+
+Additional information on jinja templating can be found at [https://jinja.palletsprojects.com/en/3.1.x/templates/#](https://jinja.palletsprojects.com/en/3.1.x/templates/#)
\ No newline at end of file
diff --git a/docs/connector-development/config-based/tutorial/5-incremental-reads.md b/docs/connector-development/config-based/tutorial/5-incremental-reads.md
index ec11512dc61a8..3270e36d76b58 100644
--- a/docs/connector-development/config-based/tutorial/5-incremental-reads.md
+++ b/docs/connector-development/config-based/tutorial/5-incremental-reads.md
@@ -112,7 +112,7 @@ definitions:
and refer to it in the stream.
This will generate time windows from the start time until the end time, where each window is exactly one day.
-The start time is defined in the config file, while the end time is defined by the `now_utc()` macro, which will evaluate to the current date in the current timezone at runtime. See the section on [string interpolation](../advanced-topics.md#string-interpolation) for more details.
+The start time is defined in the config file, while the end time is defined by the `now_utc()` macro, which will evaluate to the current date in the current timezone at runtime. See the section on [string interpolation](../advanced-topics/string-interpolation.md) for more details.
```yaml
definitions:
diff --git a/docs/connector-development/config-based/understanding-the-yaml-file/authentication.md b/docs/connector-development/config-based/understanding-the-yaml-file/authentication.md
index eb269b8cf5701..2fab490843c21 100644
--- a/docs/connector-development/config-based/understanding-the-yaml-file/authentication.md
+++ b/docs/connector-development/config-based/understanding-the-yaml-file/authentication.md
@@ -128,98 +128,9 @@ For more information see [BasicHttpAuthenticator Reference](https://docs.airbyte
### OAuth
-OAuth authentication is supported through the `OAuthAuthenticator`, which requires the following parameters:
-
-- token_refresh_endpoint: The endpoint to refresh the access token
-- client_id: The client id
-- client_secret: The client secret
-- refresh_token: The token used to refresh the access token
-- scopes (Optional): The scopes to request. Default: Empty list
-- token_expiry_date (Optional): The access token expiration date formatted as RFC-3339 ("%Y-%m-%dT%H:%M:%S.%f%z")
-- access_token_name (Optional): The field to extract access token from in the response. Default: "access_token".
-- expires_in_name (Optional): The field to extract expires_in from in the response. Default: "expires_in"
-- refresh_request_body (Optional): The request body to send in the refresh request. Default: None
-- grant_type (Optional): The parameter specified grant_type to request access_token. Default: "refresh_token"
+The OAuth authenticator is a declarative way to authenticate with an API using OAuth 2.0.
-Schema:
-
-```yaml
-OAuth:
- type: object
- additionalProperties: true
- required:
- - token_refresh_endpoint
- - client_id
- - client_secret
- - refresh_token
- - access_token_name
- - expires_in_name
- properties:
- "$parameters":
- "$ref": "#/definitions/$parameters"
- token_refresh_endpoint:
- type: string
- client_id:
- type: string
- client_secret:
- type: string
- refresh_token:
- type: string
- scopes:
- type: array
- items:
- type: string
- default: []
- token_expiry_date:
- type: string
- access_token_name:
- type: string
- default: "access_token"
- expires_in_name:
- type: string
- default: "expires_in"
- refresh_request_body:
- type: object
- grant_type:
- type: string
- default: "refresh_token"
- refresh_token_updater:
- title: Token Updater
- description: When the token updater is defined, new refresh tokens, access tokens and the access token expiry date are written back from the authentication response to the config object. This is important if the refresh token can only used once.
- properties:
- refresh_token_name:
- title: Refresh Token Property Name
- description: The name of the property which contains the updated refresh token in the response from the token refresh endpoint.
- type: string
- default: "refresh_token"
- access_token_config_path:
- title: Config Path To Access Token
- description: Config path to the access token. Make sure the field actually exists in the config.
- type: array
- items:
- type: string
- default: ["credentials", "access_token"]
- refresh_token_config_path:
- title: Config Path To Refresh Token
- description: Config path to the access token. Make sure the field actually exists in the config.
- type: array
- items:
- type: string
- default: ["credentials", "refresh_token"]
-```
-
-Example:
-
-```yaml
-authenticator:
- type: "OAuthAuthenticator"
- token_refresh_endpoint: "https://api.searchmetrics.com/v4/token"
- client_id: "{{ config['api_key'] }}"
- client_secret: "{{ config['client_secret'] }}"
- refresh_token: ""
-```
-
-For more information see [OAuthAuthenticator Reference](https://docs.airbyte.com/connector-development/config-based/understanding-the-yaml-file/reference#/definitions/OAuthAuthenticator)
+To learn more about the OAuth authenticator, see the [OAuth 2.0](../advanced-topics/oauth.md) documentation.
### JWT Authenticator
diff --git a/docs/connector-development/connector-builder-ui/authentication.md b/docs/connector-development/connector-builder-ui/authentication.md
index d4ac8796122a6..8fde6f4cf6911 100644
--- a/docs/connector-development/connector-builder-ui/authentication.md
+++ b/docs/connector-development/connector-builder-ui/authentication.md
@@ -95,6 +95,38 @@ In this case the injection mechanism is `header` and the field name is `X-CoinAP
### OAuth
+#### Declarative OAuth 2.0
+Declarative OAuth 2.0 provides a flexible way to configure any OAuth 2.0 flow by describing the exact structure and behavior of the authentication endpoints. This allows integration with OAuth 2.0 implementations that may deviate from the standard specification or have custom requirements.
+
+The configuration consists of three main components:
+
+1. **Consent URL Configuration** - Defines how to construct the URL where users grant consent:
+ - URL template with placeholders for client ID, redirect URI, and other parameters
+ - Specification of where parameters should be injected (query params, headers, etc.)
+ - Support for custom scopes and additional parameters
+
+2. **Access Token URL Configuration** - Specifies how to exchange the authorization code for an access token:
+ - Token endpoint URL
+ - Where to place client ID, client secret, and authorization code
+ - Response parsing configuration for access token and expiration
+ - Support for custom parameters and headers
+
+3. **Optional Refresh Token URL Configuration** - Defines how to refresh expired access tokens:
+ - Refresh token endpoint URL (if different from access token URL)
+ - Parameter placement for client credentials and refresh token
+ - Custom header and body configurations
+
+To learn more about the Declarative OAuth 2.0 add see a variety of example implementations please refer to the [Declarative OAuth 2.0](/connector-development/config-based/advanced-topics/oauth) documentation.
+
+
+#### Partial OAuth (legacy)
+
+The partial OAuth flow is a simpler flow that allows you to use an existing access (or refresh) token to authenticate with the API.
+
+
+The catch is that the user needs to implement the start of the OAuth flow manually to obtain the `access_token` and the `refresh_token` and pass them to the connector as a part of the `config` object.
+
+
The OAuth authentication method implements authentication using an OAuth2.0 flow with a [refresh token grant type](https://oauth.net/2/grant-types/refresh-token/) and [client credentials grant type](https://oauth.net/2/grant-types/client-credentials/).
In this scheme, the OAuth endpoint of an API is called with client id and client secret and/or a long-lived refresh token that's provided by the end user when configuring this connector as a Source. These credentials are used to obtain a short-lived access token that's used to make requests actually extracting records. If the access token expires, the connection will automatically request a new one.
diff --git a/docs/connector-development/connector-builder-ui/record-processing.mdx b/docs/connector-development/connector-builder-ui/record-processing.mdx
index 25de09503ac96..93e6dd412b4fe 100644
--- a/docs/connector-development/connector-builder-ui/record-processing.mdx
+++ b/docs/connector-development/connector-builder-ui/record-processing.mdx
@@ -23,7 +23,7 @@ Connectors built with the connector builder always make HTTP requests, receive t
The first step in converting an HTTP response into records is decoding the response body into normalized JSON objects, as the rest of the record processing logic performed by the connector expects to operate on JSON objects.
-The HTTP Response Format is used to configure this decoding by declaring what the encoding of the response body is.
+The HTTP Response Format is used to configure this decoding by declaring what the encoding of the response body is.
Each of the supported formats are explained below.
@@ -268,7 +268,7 @@ For the above example, the Iterable response format setting would result in the
allowfullscreen
>
-After decoding the response into normalized JSON objects (see [Response Decoding](#response-decoding)), the connector must then decide how to extract records from those JSON objects.
+After decoding the response into normalized JSON objects (see [Response Decoding](#response-decoding)), the connector must then decide how to extract records from those JSON objects.
The Record Selector component contains a few different levers to configure this extraction:
- Field Path
@@ -435,15 +435,15 @@ For example, say your API response looks like this:
[
{
"id": 1,
- "status": "pending"
+ "status": "pending"
},
{
"id": 2,
- "status": "active"
+ "status": "active"
},
{
"id": 3,
- "status": "expired"
+ "status": "expired"
}
]
```
@@ -453,7 +453,7 @@ You can accomplish this by setting the Record Filter to `{{ record.status != 'ex
Any records for which this expression evaluates to `true` will be emitted by the connector, and any for which it evaluates to `false` will be excluded from the output.
-Note that Record Filter value must be an [interpolated string](/connector-development/config-based/advanced-topics#string-interpolation) with the filtering condition placed inside double curly braces `{{ }}`.
+Note that Record Filter value must be an [interpolated string](/connector-development/config-based/advanced-topics/string-interpolation.md) with the filtering condition placed inside double curly braces `{{ }}`.
### Cast Record Fields to Schema Types
Sometimes the type of a field in the record is not the desired type. If the existing field type can be simply cast to the desired type, this can be solved by setting the stream's declared schema to the desired type and enabling `Cast Record Fields to Schema Types`.
diff --git a/docusaurus/docusaurus.config.js b/docusaurus/docusaurus.config.js
index 0c3b39c9af4e0..879d824a2adb0 100644
--- a/docusaurus/docusaurus.config.js
+++ b/docusaurus/docusaurus.config.js
@@ -196,7 +196,7 @@ const config = {
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
- additionalLanguages: ["bash", "json"],
+ additionalLanguages: ["bash", "diff", "json"],
},
}),
};
diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js
index cc54c965d0632..6b0f6a74cdfc1 100644
--- a/docusaurus/sidebars.js
+++ b/docusaurus/sidebars.js
@@ -286,7 +286,20 @@ const buildAConnector = {
"connector-development/config-based/understanding-the-yaml-file/reference",
],
},
- "connector-development/config-based/advanced-topics",
+ {
+ type: "category",
+ label: "Advanced Topics",
+ items: [
+ "connector-development/config-based/advanced-topics/component-schema-reference",
+ "connector-development/config-based/advanced-topics/custom-components",
+ "connector-development/config-based/advanced-topics/oauth",
+ "connector-development/config-based/advanced-topics/how-framework-works",
+ "connector-development/config-based/advanced-topics/object-instantiation",
+ "connector-development/config-based/advanced-topics/parameters",
+ "connector-development/config-based/advanced-topics/references",
+ "connector-development/config-based/advanced-topics/string-interpolation",
+ ]
+ },
],
},
@@ -653,9 +666,9 @@ module.exports = {
id: "access-management/rbac",
},
items: [
- {
- type: "doc",
- id: "access-management/role-mapping"
+ {
+ type: "doc",
+ id: "access-management/role-mapping"
},
],
},