Webhook Triggers Reference
Develop custom Valohai webhook triggers to launch pipeline runs
This reference guide covers everything you need to build custom webhook triggers. Learn about authentication methods, conditions, and how to launch webhooks programmatically from Python.
Launching webhook triggers with Python
While webhooks can be set up from outside services, you can also create custom workflows by launching webhook triggers yourself. This reference is focused on webhook triggers on Valohai, but you can also use these tools to launch webhooks at other services on the Internet that accept them.
You can use the demonstration trigger from the Launch Pipelines with Webhooks chapter as a base to experiment with.
Secrets Management
Authorization requires managing secrets to verify requests with. The following examples assume we have a secret value set in the project environment variables called WEBHOOK_TOKEN. Create it as follows:
Generate a reasonably long secret passphrase or random text. You can use your password manager to do this.
On the Valohai app, go to Project settings → Env variables
On the bottom of the list, enter
WEBHOOK_TOKENas variable name, and the secret created in step (1) to the variable value.Check the key icon and save.
Creating Webhook Triggers
Webhook triggers can be created in the project settings, under Triggers. Click "Create Trigger" and select "Webhook" as the trigger type.
Trigger behaviour can be defined with conditions that validate the webhook request and actions that can launch specific executions and pipelines in response to a valid request.
Webhook conditions reference
As with Valohai triggers in general, all conditions must simultaneously be satisfied for the trigger to launch.
Failed conditions result in a 400 Bad Request response code to the webhook, and a log entry may be recorded on the trigger log.
Web Authentication condition
This is the main tool to authenticate webhook requests with several flexible options.
Auth type and Secret key: The token's internal format and its verification data.
Static secret token: Secret key is a sequence of characters the token is compared to.
Hash-based Message Authentication Code (HMAC): Secret Key is a shared secret with the sender that is used to generate the HMAC signature.
JSON Web Token (JWT): Secret key is either a symmetric key or the asymmetric public key that verifies the given JWT-format token.
The secret key can use (secret) project environment variables using {env:MY_ENV_VAR}. This is very useful if you have several webhooks from the same provider reusing the same verification secret.
HMAC Basestring Format: HMAC only. This describes the structure of the HMAC signature's source data, which can use the request body content as well as select headers from the request. You can include the entire request body with {body}. You can include request header values with {header:My-Header}. If the named header is not found in the request, the condition will always fail. This field is typically used to represent a static prefix, punctuation or timestamp value in the HMAC signature.
The remaining options describe how the token to compare against is acquired.
Token Lookup Namespace: Where to look for the authentication token?
HTTP Header: Supplied within the request headers. Key is the header name in standard
X-Http-Headerformat.Querystring: Supplied as part of the URL after the question mark:
https://app.valohai.com/api/v0/launch/.../?search=sharks&size=3would have the querystring keysearchwith the valuesharks, and the keysizewith the value3.URL Encoded Body: Supplied as part of the request body content, in the same format as querystring
JSON Body: Supplied as part of the request body content, using JSON format. Note: Only top level keys are supported.
Token Lookup Key: What part of the namespace contains the authentication token?
Value Prefix: The token often has a static prefix that is not part of the token. This field can be used to cut the prefix away prior to verifying the remaining token.
Static token authorization example
Static token authorization is handled with a Web Request Authentication trigger condition. This is the simplest authorization method as a shared, static secret is passed by the webhook sender within the request and compared with the stored secret on the Valohai project.
Add a static token authentication condition with these steps:
For Auth Type, select "Static Secret Token"
For Token Lookup Namespace, select "HTTP Header"
For Token Lookup Key, type
AuthorizationFor Secret Key, enter
{env:WEBHOOK_TOKEN}Leave Value prefix empty.
Launch a webhook using urllib (no install required):
import os
import urllib.request
import urllib.parse
urllib.request.urlopen(urllib.request.Request(
'<paste the webhook URL here>',
data=urllib.parse.urlencode({
'hello': 'valohai',
'prompt': 'draw me a shark'
}).encode(),
headers={
'Authorization': os.getenv("WEBHOOK_TOKEN")
}
))Launch a webhook with requests (install it with pip install requests or add requests to your requirements.txt):
import os
import requests
requests.post(
'<paste the webhook URL here>',
data={'hello': 'valohai', 'prompt': 'draw me a shark'},
headers={'Authorization': os.getenv("WEBHOOK_TOKEN")}
)Hash-based Message Authentication Code (HMAC) authentication example
Hash-based Message Authentication Code (HMAC) uses the shared secret to create a check value derived from the request's contents, which is not a secret. The check value is then generated again by the condition and compared with the value sent with the request to validate it. HMAC is more secure than a simple shared token, as the token is never transmitted within the request.
Add a HMAC authentication condition with these steps:
For Auth Type, select "Hash-based Message Authentication Code"
For Token Lookup Namespace, select "Header"
For Token Lookup Key, type
AuthorizationFor Secret Key, enter
{env:WEBHOOK_TOKEN}Leave Value prefix empty.
For Algorithm, select
SHA256
Launch the trigger with this example Python code:
import hmac
import os
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({
'hello': 'valohai',
'prompt': 'draw me a shark'
}).encode()
calculated_hmac = hmac.new(
key=os.getenv("WEBHOOK_TOKEN").encode(),
msg=data,
digestmod='sha256',
).hexdigest()
urllib.request.urlopen(urllib.request.Request(
'<paste the webhook URL here>',
data=data,
headers={
'Authorization': calculated_hmac
}
))JSON Web Token (JWT) authentication example
JSON Web Tokens (JWT) use a shared or asymmetric secret to sign a token authenticating the request. A new, quickly expiring token can be generated for each webhook request. Like HMAC, the shared secret is not transmitted with the request.
Asymmetric algorithms (e.g. RS256) can be used to avoid sharing secrets. To do so, create an RSA keypair (private and public key). Encode the JWT with the private key and set the WEBHOOK_TOKEN to the corresponding public key. The public key only allows verifying that the token was created by the private key. This example uses a symmetric algorithm.
Add a JWT authentication condition with these steps:
For Auth Type, select "JSON Web Token"
For Token Lookup Namespace, select "HTTP Header"
For Token Lookup Key, type
AuthorizationFor Secret Key, enter
{env:WEBHOOK_TOKEN}Leave Value prefix empty.
For Algorithm, select
HS256
Launch the trigger with this example Python code. You will need PyJWT installed to run this, which you can get with e.g. pip install pyjwt.
import jwt
import os
import time
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({
'hello': 'valohai',
'prompt': 'draw me a shark'
}).encode()
token = jwt.encode(
{'ts': int(time.time())},
key=os.getenv("WEBHOOK_TOKEN"),
headers={'exp': int(time.time() + 60)}
)
urllib.request.urlopen(urllib.request.Request(
'<paste the webhook URL here>',
data=data,
headers={
'Authorization': token
}
))More Web Authentication condition examples
Here are some more examples to help match webhook authorization headers with Valohai trigger conditions. You can inspect how webhook requests look like by configuring them to deliver to a custom Web server or a service like Smee. Valohai does not provide direct access to Webhook request contents as they may contain sensitive information.
Incoming header: Authorization: JWT ey...(JWT)
Auth type: JWT
Token lookup namespace: HTTP Header
Token lookup key:
AuthorizationValue prefix:
JWT. Note: Remember the trailing space. The prefix is cut from the beginning of the supplied value exactly.Secret key: Secret key that verifies the JWT
Incoming header: X-Hmac-Signature: v0=u2jhlpq...(HMAC signature)
The HMAC comparison is specified to use the static string "hmac", a value from another header "X-Hmac-Timestamp" and the request body, delimited with the colon character ":".
Auth type: HMAC
Token lookup namespace: HTTP Header
Token lookup key:
X-Hmac-SignatureValue prefix:
v0=HMAC Basestring Format:
hmac:{header:X-Hmac-Timestamp}:{body}Secret key: Shared secret with the sender
Incoming request content: token=pat_842717_...(static token)&event_type=new_data&...
Auth type: Static token
Token lookup namespace: URL Encoded body
Token lookup key: "token"
Secret key: "pat_842717_...(static token)"
Web Timestamp condition
Timestamp conditions are typically used combined with HMAC authentication conditions to make HMAC-signed requests expire after a short period, which protects against replay attacks where a valid request is recorded and sent again later.
Timestamp lookup namespace and lookup key work the same way as web authentication.
If the timestamp cannot be found, or is found but is more than Drift tolerance seconds away from current time, the condition fails.
The timestamp must be a UNIX timestamp as seconds.
Web Timestamp with HMAC authentication example
Add a Web Request Authentication condition using HMAC with these steps:
For Auth Type, select "Hash-based Message Authentication Code"
For Token Lookup Namespace, select "HTTP Header"
For Token Lookup Key, type
AuthorizationFor Secret Key, enter
{env:WEBHOOK_TOKEN}For HMAC Basestring Format, type
prefix.{body}.{header:Request-Timestamp}Leave Value prefix empty.
For Algorithm, select "SHA256"
Add a Web Request Timestamp condition with these steps:
For Token Lookup Namespace, select "HTTP Header"
For Token Lookup Key, type
Request-TimestampFor Tolerance, type
60(this is in seconds)
Launch this trigger with this example Python code:
import time
import hmac
import os
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({
'hello': 'valohai',
'prompt': 'draw me a shark'
}).encode()
timestamp = int(time.time())
calculated_hmac = hmac.new(
key=os.getenv("WEBHOOK_TOKEN").encode(),
msg=f"prefix.{data.decode()}.{timestamp}".encode(),
digestmod='sha256',
).hexdigest()
urllib.request.urlopen(urllib.request.Request(
'<paste the webhook URL here>',
data=data,
headers={
'Authorization': calculated_hmac,
'Request-Timestamp': str(timestamp),
}
))Rate Limit condition
Rate limit conditions can prevent triggers from launching more often than you intend. You should set a reasonable rate limit to protect against accidentally launching too many triggered workloads.
Set a time Period (in seconds) during which at most Quota of triggers can be launched. This condition fails if the trigger being launched would exceed the quota.
Several rate limits can be applied at once to allow e.g. a large daily quota, but also a smaller hourly quota that you can't use the whole day's quota at once.
Webhook Actions Reference
Web Response Text & JSON
These actions can customize successful webhook responses. They can only show static content. Failed response content cannot be customized. The default response is ok (text/plain). Only the first web response action will be used.
For Response Text, the content type will be text/plain.
For Response JSON, the content type will be application/json.
You can use the {run_id} placeholder to include a reference to the trigger run that the webhook has launched. This reference can be used to request information about the trigger's results, such as created executions using the webhook run info endpoint.
Run Execution
Webhook-specific parameter Payload input name allows setting the webhook request body as an input on the execution being launched. The execution step must have a matching declared input in the YAML.
The execution will receive the untouched request body into that input when launched through the webhook, and is responsible for parsing and processing it.
Run Pipeline
Webhook-specific parameter Payload input name allows setting the webhook request body as an input on one of the executions in the pipeline being launched. The format is nodename.input_name. The node of the specified name must be an execution node and the node's execution step must have matching a declared input in the YAML.
Last updated
Was this helpful?
