Skip to main content

Check out Port for yourself ➜ 

Secret

Use secret inputs to pass sensitive data to action backends. An extra processing layer encrypts the values, ensuring Port never logs or stores them.

Port offers two encryption options:

  • Port-managed encryption - Uses your organization's client secret as the encryption key.
  • Client-side encryption - Gives you full control over key management by using your own RSA key pair.

Common secret usage

The secret input type can be used for sensitive information, such as:

  • Cloud secrets
  • Passwords
  • API keys
  • Secret tokens
  • SSL/TLS certificates
  • Private keys

Limitations

Secret inputs are not supported for the GitHub Ocean invocation method.

Secret input structure

A secret input is defined as a regular input with the additional encryption field that specifies the encryption method.

Encryption options

Port-managed encryption uses the AES-256-GCM algorithm with your organization's client secret as the encryption key.

{
"mySecretInput": {
"title": "My secret input",
"icon": "My icon",
"type": "string",
"encryption": "aes256-gcm",
"description": "My secret input"
}
}

The encrypted value is formatted as: [IV (16 bytes)][ciphertext][MAC (16 bytes)], encoded in base64. The encryption key is the first 32 bytes of your organization's client secret.

Supported types

Secret inputs support both string and object types. You can use either encryption method with both types.

{
"mySecretInput": {
"title": "My secret input",
"icon": "My icon",
"type": "string",
"encryption": "aes256-gcm",
"description": "My secret input"
}
}

Multi-line secret inputs

For sensitive information that contains line breaks, such as SSL/TLS certificates, private keys, or configuration files, you can combine the multi-line text format with encryption.

Multi-line secret inputs provide a larger text area for input and support both encryption methods. You can decrypt them using the same methods shown in the handling the payload section.

This is particularly useful when you need to send certificates to your backend workflows. For example, when configuring SSL certificates for cloud resources or setting up authentication with certificate-based credentials.

Multiline secrets are not masked

Unlike single-line secret inputs which are masked with asterisks, multi-line secret inputs display the actual text as you type. The value is still encrypted when sent to your backend and is never logged or saved by Port.

{
"certificateInput": {
"title": "SSL certificate",
"icon": "Lock",
"type": "string",
"format": "multi-line",
"encryption": "aes256-gcm",
"description": "Paste your SSL certificate"
}
}

This configuration creates a multi-line text area where users can paste certificates or other multiline secrets. The value will be encrypted before being sent to your backend.

Common use cases

Multi-line secret inputs are ideal for:

  • SSL/TLS certificates and certificate chains.
  • Private keys (RSA, EC, etc.).
  • JSON or YAML configuration files containing secrets.
  • Multi-line API keys or tokens.
  • SSH keys.

Handling the payload

The payload sent to your infrastructure will contain the encrypted value of your secret property inputs. To make use of your secret inputs, you will need to decrypt them.

Examples

Examples for decrypting properties encrypted with Port-managed aes256-gcm encryption.

The following example uses the flask and pycryptodome packages:

import base64
import json
import os

from flask import Flask, request
from Crypto.Cipher import AES

PORT_CLIENT_SECRET = 'YOUR PORT CLIENT SECRET'
PROPERTY_IS_JSON = False # whether the property is defined as json or not (string otherwise)

app = Flask(__name__)

@app.route('/', methods=['POST'])
def webhook():
# initialize the aes cipher
key = PORT_CLIENT_SECRET[:32].encode()

req = request.get_json(silent=True, force=True)
encrypted_property_value = base64.b64decode(req.get('payload').get('properties').get('secret-property'))

iv = encrypted_property_value[:16]
ciphertext = encrypted_property_value[16:-16]
mac = encrypted_property_value[-16:]

cipher = AES.new(key, AES.MODE_GCM, iv)

# decrypt the property
decrypted_property_value = cipher.decrypt_and_verify(ciphertext, mac)
property_value = json.loads(decrypted_property_value) if PROPERTY_IS_JSON else decrypted_property_value

return property_value # this is the original value the user sent

if __name__ == '__main__':
port = int(os.getenv('PORT', 80))

print("Starting app on port %d" % port)

app.run(debug=False, port=port, host='0.0.0.0')