GitHub
GitHub integration actions allow workflows to trigger GitHub Actions workflows, manage pull requests, and create issues directly using your installed GitHub Ocean integration.
Prerequisites
- A GitHub Ocean integration installed in your Port organization.
- Actions processing must be enabled on your integration:
- Hosted by Port / UI / OAuth installations: actions processing is enabled automatically.
- Self-hosted (Helm or Docker): actions processing is disabled by default and must be explicitly enabled. See Enable actions processing (self-hosted) below.
- Your GitHub token or app must have the appropriate permissions:
- Workflow actions: the workflow must exist in the target repository and accept
workflow_dispatchevents. - Pull request actions: write access to pull requests in the target repositories.
- Issue actions: write access to issues in the target repositories.
- Workflow actions: the workflow must exist in the target repository and accept
- To run GitHub actions as the user who triggered the Port workflow (not the GitHub App bot), enable identity propagation on the node. Self-hosted Ocean only.
Enable actions processing (self-hosted)
If you installed the GitHub Ocean integration as hosted by Port (via the UI or OAuth), actions processing is enabled automatically and you can skip to Configuration.
For self-hosted deployments (Kubernetes/Helm or Docker), the actions processor is disabled by default. You need to enable it explicitly using the flags below, depending on how you deployed the integration:
- Helm
- Docker
Pass the following flags when installing or upgrading the Helm chart:
helm upgrade --install github-ocean port-labs/port-ocean \
--set actionsProcessor.enabled=true \
--set liveEvents.baseUrl=<YOUR_INTEGRATION_BASE_URL> \
# ... rest of your values
actionsProcessor.enabled=true- enables the actions processor so the integration can receive and execute GitHub Actions dispatch requests from Port.liveEvents.baseUrl=<YOUR_INTEGRATION_BASE_URL>- setsOCEAN__BASE_URL, which is required whenreportWorkflowStatusis enabled (the default). Port uses this URL to receive webhook events from GitHub and update the action run status in real time. The URL must be reachable from GitHub.
If you use a dedicated actions processor worker (actionsProcessor.worker.enabled=true), route this URL to the actions processor worker service. Otherwise, route it to the main integration service.
Add the following environment variables to your Docker run command or docker-compose configuration:
docker run \
-e OCEAN__ACTIONS_PROCESSOR__ENABLED=true \
-e OCEAN__BASE_URL=<YOUR_INTEGRATION_BASE_URL> \
# ... rest of your env vars
ghcr.io/port-labs/port-ocean-github-ocean:latest
reportWorkflowStatus?By default, Port automatically updates the action/automation run status in Port when the triggered GitHub workflow finishes. This requires GitHub to send a webhook event back to the integration. If the integration's base URL is not set, Port cannot receive this callback and the run status will not be updated automatically.
To disable this behavior, set reportWorkflowStatus: false in the invocationMethod of your action, or turn off the Report workflow status toggle in the UI.
If you disable automatic reporting, add a step in your GitHub workflow that uses port-labs/port-github-action@v1 with the PATCH_RUN operation to update the action run status in Port. See Port's GitHub action for configuration details.
Configuration
All GitHub integration actions share the same node structure:
| Field | Type | Description |
|---|---|---|
type | string | Required. Must be "INTEGRATION_ACTION". |
installationId | string | Required. Your GitHub integration installation ID. |
integrationProvider | string | Required. Must be "github-ocean". |
integrationInvocationType | enum | Required. One of the values listed in available actions. |
integrationActionExecutionProperties | object | Required. Properties for the selected action. |
Available actions
Each action is selected with the integrationInvocationType field:
| Action | Invocation type | Description |
|---|---|---|
| Trigger a GitHub workflow | dispatch_workflow | Dispatch a GitHub Actions workflow and optionally wait for its result |
| Create a pull request | create_pull_request | Open a pull request between two branches |
| Update a pull request | update_pull_request | Change a pull request's title, description, state, or base branch |
| Close a pull request | close_pull_request | Close a pull request without merging it |
| Merge a pull request | merge_pull_request | Merge a pull request using a specified merge strategy |
| Submit a pull request review | review_pull_request | Approve, request changes, or comment on a pull request |
| Create a pull request comment | create_pr_comment | Add a comment to a pull request |
| Edit a pull request comment | edit_pr_comment | Edit an existing pull request comment |
| Delete a pull request comment | delete_pr_comment | Delete a pull request comment |
| Create an issue | create_issue | Create a new issue in a repository |
| Edit an issue | edit_issue | Update an issue's title, description, state, labels, or assignees |
| Close an issue | close_issue | Close an issue with a specified reason |
The remaining sections describe the execution properties of each action.
Workflow actions
Trigger a GitHub workflow
Dispatches a GitHub Actions workflow. Set integrationInvocationType to "dispatch_workflow".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user name (e.g., port-labs). |
repo | string | Required. Repository name (e.g., my-repo). |
workflow | string | Required. Workflow filename (e.g., deploy.yml) or workflow ID. |
workflowInputs | object | Input parameters to pass to the workflow. |
reportWorkflowStatus | boolean | Whether to report workflow status back to Port. |
Basic example
Example (click to expand)
Trigger a GitHub Actions deployment workflow, passing environment and version from the trigger inputs:
{
"identifier": "trigger-github-workflow",
"title": "Trigger GitHub Deployment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "dispatch_workflow",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"workflow": "deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}"
}
}
}
}
Workflow inputs
Workflow inputs (click to expand)
Pass inputs to your GitHub Actions workflow. Values can be static or dynamically resolved from workflow outputs:
{
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "my-repo",
"workflow": "build-and-deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}",
"dry_run": "{{ .outputs.trigger.dryRun | tostring }}"
}
}
}
GitHub Actions workflow inputs are always strings. Use JQ functions like tostring to convert non-string values.
Status reporting
Status reporting (click to expand)
By default, Port monitors the triggered workflow and updates the workflow node status when it completes. To opt out:
{
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "my-repo",
"workflow": "deploy.yml",
"reportWorkflowStatus": false
}
}
When reportWorkflowStatus is false, the node is left in progress after the workflow is dispatched, and it is up to you to report its outcome back to Port (for example, by calling the Port API from a step in your workflow).
When reportWorkflowStatus is true (the default), Port monitors the GitHub Actions workflow run via webhook events and reports success or failure when it completes.
Automatic workflow status updates require live events to be enabled on the integration. Live events are enabled automatically for integrations hosted by Port, but must be manually configured for self-hosted installations.
Pull request actions
Manage a pull request
Create, update, close, or merge a pull request.
- Create
- Update
- Close
- Merge
Opens a new pull request in a GitHub repository. Set integrationInvocationType to "create_pull_request".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
title | string | Required. Title of the pull request. |
head | string | Required. Branch where your changes are implemented. |
base | string | Required. Branch you want the changes pulled into. |
body | string | Description of the pull request. |
draft | boolean | Whether to create the pull request as a draft. Default: false. |
Basic example (click to expand)
Open a pull request from a feature branch into main:
{
"identifier": "create-pull-request",
"title": "Open Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.prTitle }}",
"head": "{{ .outputs.trigger.featureBranch }}",
"base": "main",
"body": "{{ .outputs.trigger.description }}",
"draft": false
}
}
}
Changes an existing pull request's title, description, state, or base branch. Set integrationInvocationType to "update_pull_request".
Use this action when you need to edit pull request metadata. For the common cases of closing or merging a pull request, prefer the Close and Merge tabs in this section.
Execution properties
At least one optional property is required, since an update with no changes is rejected.
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
prNumber | string | Required. The pull request number. |
title | string | New title for the pull request. |
body | string | New description for the pull request. |
state | string | New state: "open" or "closed". |
base | string | New base branch for the pull request. |
Basic example (click to expand)
Rename a pull request and update its description:
{
"identifier": "update-pull-request",
"title": "Update Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "update_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"title": "{{ .outputs.trigger.newTitle }}",
"body": "{{ .outputs.trigger.newDescription }}"
}
}
}
Closes an open pull request without merging it. Set integrationInvocationType to "close_pull_request".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
prNumber | string | Required. The pull request number to close. |
Basic example (click to expand)
{
"identifier": "close-pull-request",
"title": "Close Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "close_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}"
}
}
}
Merges a pull request using the specified merge strategy. Set integrationInvocationType to "merge_pull_request".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
prNumber | string | Required. The pull request number to merge. |
mergeMethod | string | Merge strategy: "merge", "squash", or "rebase". Default: "merge". |
commitTitle | string | Title for the merge commit (used with merge and squash methods). |
commitMessage | string | Extra detail for the merge commit (used with merge and squash methods). |
The available merge methods depend on your repository settings. If a method is not enabled for the repository, GitHub will reject the request. See GitHub's merge method documentation for details.
Basic example (click to expand)
Merge a pull request using the squash strategy:
{
"identifier": "merge-pull-request",
"title": "Merge Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "merge_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"mergeMethod": "squash",
"commitTitle": "{{ .outputs.trigger.commitTitle }}"
}
}
}
Submit a pull request review
Submits a review on a pull request: approve, request changes, or leave a comment. Set integrationInvocationType to "review_pull_request".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
prNumber | string | Required. The pull request number to review. |
event | string | Required. Review action: "APPROVE", "REQUEST_CHANGES", or "COMMENT". |
body | string | Review comment text. Required when event is "REQUEST_CHANGES". |
APPROVE- approves the pull request. Thebodyfield is optional.REQUEST_CHANGES- requests changes. Thebodyfield is required and should describe what needs to change.COMMENT- leaves a general review comment without approving or requesting changes.
Basic example (click to expand)
Submit an approval review on a pull request:
{
"identifier": "review-pull-request",
"title": "Review Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "review_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"event": "APPROVE",
"body": "Looks good to me!"
}
}
}
Pull request comments
Create, edit, or delete comments on a pull request.
- Create
- Edit
- Delete
Adds a comment to a pull request. Set integrationInvocationType to "create_pr_comment".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
prNumber | string | Required. The pull request number to comment on. |
body | string | Required. The comment text. |
Basic example (click to expand)
Add a comment to a pull request:
{
"identifier": "create-pr-comment",
"title": "Comment on Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pr_comment",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"body": "{{ .outputs.trigger.comment }}"
}
}
}
Edits an existing comment on a pull request. Set integrationInvocationType to "edit_pr_comment".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
commentId | string | Required. The ID of the comment to edit. |
body | string | Required. The updated comment text. |
Basic example (click to expand)
Edit an existing pull request comment:
{
"identifier": "edit-pr-comment",
"title": "Edit Pull Request Comment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "edit_pr_comment",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"commentId": "{{ .outputs.trigger.commentId }}",
"body": "{{ .outputs.trigger.updatedComment }}"
}
}
}
Deletes a comment from a pull request. Set integrationInvocationType to "delete_pr_comment".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
commentId | string | Required. The ID of the comment to delete. |
Basic example (click to expand)
Delete a pull request comment:
{
"identifier": "delete-pr-comment",
"title": "Delete Pull Request Comment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "delete_pr_comment",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"commentId": "{{ .outputs.trigger.commentId }}"
}
}
}
Issue actions
Manage an issue
Create, edit, or close an issue.
- Create
- Edit
- Close
Creates a new issue in a GitHub repository. Set integrationInvocationType to "create_issue".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
title | string | Required. Title of the issue. |
body | string | Description of the issue. |
labels | array | Labels to apply to the issue. |
assignees | array | GitHub usernames to assign to the issue. |
Basic example (click to expand)
Create an issue with labels and an assignee:
{
"identifier": "create-issue",
"title": "Create Issue",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_issue",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.issueTitle }}",
"body": "{{ .outputs.trigger.description }}",
"labels": ["bug", "priority:high"],
"assignees": ["{{ .outputs.trigger.assignee }}"]
}
}
}
Updates an existing issue's title, description, state, labels, or assignees. Set integrationInvocationType to "edit_issue".
Use this action when you need to change issue metadata. To close an issue with a specific completion reason in GitHub's UI, prefer the dedicated Close tab above, or set state to "closed" together with stateReason.
Execution properties
At least one optional property is required, since an update with no changes is rejected.
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
issueNumber | string | Required. The issue number. |
title | string | New title for the issue. |
body | string | New description for the issue. |
state | string | New state: "open" or "closed". When closing, set stateReason or use "close_issue". |
stateReason | string | When state is "closed": "completed" or "not_planned". Default: "completed". Ignored when state is "open". |
labels | array | Replaces all labels on the issue (GitHub's issue PATCH is not additive). |
assignees | array | Replaces issue assignees (GitHub's issue PATCH is not additive). |
Sending labels or assignees replaces the issue's current values. To keep existing labels or assignees, include them in the array together with any additions.
Basic example (click to expand)
Update an issue's title and add a label:
{
"identifier": "edit-issue",
"title": "Edit Issue",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "edit_issue",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"issueNumber": "{{ .outputs.trigger.issueNumber }}",
"title": "{{ .outputs.trigger.newTitle }}",
"labels": ["triaged"]
}
}
}
Closes an issue with a specified reason. Set integrationInvocationType to "close_issue".
Execution properties
| Field | Type | Description |
|---|---|---|
org | string | Required. GitHub organization or user that owns the repository. |
repo | string | Required. Repository name. |
issueNumber | string | Required. The issue number to close. |
stateReason | string | Reason for closing: "completed" or "not_planned". Default: "completed". Invalid values are rejected before the GitHub API is called. |
Basic example (click to expand)
Close an issue as not planned:
{
"identifier": "close-issue",
"title": "Close Issue",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "close_issue",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"issueNumber": "{{ .outputs.trigger.issueNumber }}",
"stateReason": "not_planned"
}
}
}
Complete workflow examples
Deploy a service with GitHub Actions (click to expand)
A self-service deployment workflow that triggers GitHub Actions, waits for completion, and updates the service entity with deployment details:
{
"identifier": "deploy-with-github",
"title": "Deploy Service with GitHub Actions",
"icon": "Github",
"description": "Trigger a deployment using GitHub Actions",
"nodes": [
{
"identifier": "trigger",
"title": "Request Deployment",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"service": {
"type": "string",
"format": "entity",
"blueprint": "service",
"title": "Service"
},
"environment": {
"type": "string",
"title": "Environment",
"enum": ["staging", "production"]
},
"version": {
"type": "string",
"title": "Version",
"description": "Git tag or commit SHA"
}
},
"required": ["service", "environment", "version"]
}
}
},
{
"identifier": "trigger-deploy",
"title": "Trigger GitHub Deployment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "gh-integration-123",
"integrationProvider": "github-ocean",
"integrationInvocationType": "dispatch_workflow",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.service }}",
"workflow": "deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}"
},
"reportWorkflowStatus": true
}
}
},
{
"identifier": "update-entity",
"title": "Update Service Status",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "service",
"mapping": {
"identifier": "{{ .outputs.trigger.service }}",
"properties": {
"lastDeployedVersion": "{{ .outputs.trigger.version }}",
"lastDeployedEnvironment": "{{ .outputs.trigger.environment }}",
"lastDeployedAt": "{{ now | todateiso8601 }}"
}
}
}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "trigger-deploy"
},
{
"sourceIdentifier": "trigger-deploy",
"targetIdentifier": "update-entity"
}
]
}
Open a pull request from a feature branch (click to expand)
A self-service workflow that opens a pull request from a feature branch:
{
"identifier": "create-github-pull-request-workflow",
"title": "Open a Pull Request",
"icon": "Github",
"description": "Open a pull request from a feature branch",
"nodes": [
{
"identifier": "trigger",
"title": "Request PR Creation",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"repository": {
"type": "string",
"title": "Repository"
},
"featureBranch": {
"type": "string",
"title": "Feature branch"
},
"prTitle": {
"type": "string",
"title": "PR title"
},
"description": {
"type": "string",
"title": "Description"
}
},
"required": ["repository", "featureBranch", "prTitle"]
}
}
},
{
"identifier": "create-github-pull-request",
"title": "Open Pull Request",
"icon": "Github",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "gh-integration-123",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.prTitle }}",
"head": "{{ .outputs.trigger.featureBranch }}",
"base": "main",
"body": "{{ .outputs.trigger.description }}"
}
}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "create-github-pull-request"
}
]
}
Identity propagation
Identity propagation lets a workflow integration action call the downstream platform as the user who triggered the run.
Identity propagation is only supported on self-hosted Ocean integrations.
How it works
When a node run needs authentication, Port sends Ocean a short-lived OIDC token. Ocean checks its vault for a token stored for the triggering user. If none exists, the run pauses and prompts the user to authenticate through an OAuth flow hosted by Ocean. Once approved, Ocean stores the token in the user's vault entry, resumes the run, and executes the action with the user's own credentials.
The user sees a waiting for authentication state on the node, along with an Authenticate action in the workflow run page and in an Inbox notification.
Requirements on Ocean
- Actions processing enabled (
OCEAN__ACTIONS_PROCESSOR__ENABLED=true, or HelmactionsProcessor.enabled=true). - Identity propagation enabled (
OCEAN__IDENTITY_PROPAGATION__ENABLED=true, or HelmidentityPropagation.enabled=true). Helm fails install or upgrade if this is true withoutactionsProcessor.enabledand a publicliveEvents.baseUrl. - A publicly reachable base URL (
OCEAN__BASE_URL, or HelmliveEvents.baseUrl). Ocean registers{baseUrl}/v1/oauth-broker/authorizeon startup. If the URL isn't public, the OAuth flow cannot be completed. - An OAuth application with the downstream provider, using
{baseUrl}/v1/oauth-broker/callbackas the redirect URI. Provider-specific setup steps are in the Setup section below. - OAuth app credentials on the integration. Set
identityOauthClientIdandidentityOauthClientSecret(andidentityOauthTenantIdfor Azure DevOps) in Helmintegration.config/integration.secrets, or asOCEAN__INTEGRATION__CONFIG__IDENTITY_OAUTH_*in Docker. Authorize and token URLs come from the integration's existing host or tenant settings. - A vault for storing tokens (see below). AWS Secrets Manager is supported out of the box.
Each Ocean process hosts one integration and one OAuth provider. If you run more than one supported integration, each is a separate Ocean deployment with its own OAuth application and vault entries.
Restart the integration after changing OCEAN__BASE_URL so it re-registers its broker URL. A resync alone doesn't do this.
Helm example (OAuth client values are integration-specific; see Setup):
identityPropagation:
enabled: true
actionsProcessor:
enabled: true
liveEvents:
baseUrl: https://ocean.example.com
The vault
Ocean stores each user's downstream token in a vault, keyed by organization, actor, and integration. Default is AWS Secrets Manager:
OCEAN__IDENTITY_PROPAGATION__VAULT__TYPE="aws_secrets_manager"
OCEAN__IDENTITY_PROPAGATION__VAULT__SECRET_PREFIX="port/tokens"
OCEAN__IDENTITY_PROPAGATION__VAULT__AWS_REGION="<your-region>"
Helm equivalent: identityPropagation.vault.type, identityPropagation.vault.secretPrefix, and identityPropagation.vault.awsRegion. Prefer an IAM role on the pod over static awsAccessKeyId / awsSecretAccessKey.
That role needs secretsmanager:CreateSecret, secretsmanager:PutSecretValue, and secretsmanager:GetSecretValue on {secretPrefix}/* (default port/tokens/*). Ocean writes {secretPrefix}/{orgId}/{actorId}/{target} on the first successful OAuth callback, then updates the same secret later. Without those three actions the callback cannot store the token, and the failure comes from the vault client.
Bringing your own vault
Ocean only ships an AWS Secrets Manager vault by default. To use a different store (HashiCorp Vault, GCP Secret Manager, your own database, etc.), write your own vault client:
-
Import
VaultClientandTokenRecordfromport_ocean.identity_propagation.vault.base. -
Create a class that subclasses
VaultClientand implements its two methods,readandwrite, against your store. -
In your integration's startup code, assign an instance of your class to
ocean.app.vault_client. Ocean calls this instance instead of the built-in AWS client.from port_ocean.identity_propagation.vault.base import VaultClient, TokenRecordclass MyVaultClient(VaultClient):async def read(self, org_id: str, actor_id: str, target: str) -> TokenRecord | None:... # look up and return the stored record, or None if there isn't oneasync def write(self, org_id: str, actor_id: str, target: str, record: TokenRecord) -> None:... # store the recordocean.app.vault_client = MyVaultClient()TokenRecordholdsaccess_token, an optionalrefresh_token, and an optionalexpires_at.
Networking requirements
OCEAN__BASE_URL(HelmliveEvents.baseUrl) must be reachable from the browsers of everyone who triggers workflows with identity propagation enabled.- The same URL must be reachable from the downstream provider, since it redirects the user's browser back there after approval.
- After OAuth, Ocean redirects the browser to Port's app. Set Helm
port.appUrl(OCEAN__PORT__APP_URL) when that URL cannot be derived fromport.baseUrl(for example staging, whereapi.does not map toapp.).
Setup
You don't create a new app for this. Instead, configure the same GitHub App your GitHub integration already created on install:
-
Go to your GitHub organization's Settings > Developer settings > GitHub Apps, and select that app.
-
Under Identifying and authorizing users, select Add redirect URI and enter
{baseUrl}/v1/oauth-broker/callback, where{baseUrl}is yourOCEAN__BASE_URL(HelmliveEvents.baseUrl). -
Copy the Client ID and generate a Client secret.
-
Put those values on the integration. Authorize and token URLs are derived from
githubHost.- Helm
- Docker
identityPropagation:enabled: trueactionsProcessor:enabled: trueliveEvents:baseUrl: https://ocean.example.comintegration:config:identityOauthClientId: "<client-id>"secrets:identityOauthClientSecret: "<client-secret>"OCEAN__IDENTITY_PROPAGATION__ENABLED="true"OCEAN__INTEGRATION__CONFIG__IDENTITY_OAUTH_CLIENT_ID="<client-id>"OCEAN__INTEGRATION__CONFIG__IDENTITY_OAUTH_CLIENT_SECRET="<client-secret>"Set
enableIdentityPropagation:trueon the node's configuration.
Limitations
Run expiry: Runs that remain unprocessed for more than 3 hours are automatically expired and will not be executed.