Webhooks
Corbado leverages webhooks to exchange data with your backend and current user management system. Corbado not only uses webhooks to push data to your backend but also uses the response from your backend to provide a smooth user experience (bi-directional data exchange).
Corbado's usage of webhooks allows the lighweight integration of Corbado into existing systems without major changes to your current authentication and user management.
You will need to configure the endpoints of your application which will receive the data from Corbado. You can do this by clicking on "Settings" - "Webhooks" - "Configuration":
Please add a webhooks URL that will be the endpoint exposed by your backend which will process the data:

Webhooks URL
To communicate securely with your backend, HTTP basic authentication is used. Please set an HTTP basic authentication username and password in the developer panel (this authentication information needs to be set up in your backend as well).

Webhooks authentication
Once you're ready, click on "Save changes".
The corresponding code in your backend application could look like this:
PHP
Node.js
#[Route('/webhooks', name: 'corbado', methods: 'POST')]
public function corbadoWebhook(UserRepository $userRepo, Request $request, string $webhookUsername, string $webhookPassword): Response
{
// Create new webhook instance with "webhookUsername" and "webhookPassword". Both must be
// set in the developer panel (https://app.corbado.com) and are used to secure your
// webhook (this one here) with basic authentication.
$webhook = new Webhook('webhookUsername', 'webhookPassword');
// Handle authentication so your webhook is secured (basic authentication). If username
// and/or password are invalid handleAuthentication() will send HTTP status code
// 401 (Unauthorized) and terminate/exit execution here.
$webhook->handleAuthentication();
// Check if request has been made with POST. For Corbado webhooks
// only POST is allowed/used.
if (!$webhook->isPost()) {
throw new Exception('Only POST is allowed');
}
...
}
const {Webhook, webhookMiddleware} = require('corbado-webhook');
const webhook = new Webhook();
// Here, you can define the webhook username and password that you also
// have set in the Corbado developer panel
app.post('/webhooks', webhookMiddleware("webhookUsername", "webhookPassword"), (req, res) => {
...
}
To ensure that your webhooks are working properly and returning the correct response, you can define test data to check the two most important actions: requesting login information and password verification.
Please provide a valid pair of username and password. This test will check if the password verification of your existing authentication is connected properly.

PHP
Node.js
#[Route('/webhooks', name: 'corbado', methods: 'POST')]
public function corbadoWebhook(UserRepository $userRepo, Request $request, string $webhookUsername, string $webhookPassword): Response
{
// Get the webhook action and act accordingly. Every Corbado
// webhook has an action.
switch ($webhook->getAction()) {
...
// Handle the "passwordVerify" action which basically checks
// if the given username and password are valid.
case $webhook::ACTION_PASSWORD_VERIFY:
$request = $webhook->getPasswordVerifyRequest();
// Now check if the given username and password is
// valid. Implement verifyPassword() function below.
$webhook->sendPasswordVerifyResponse($this->verifyPassword($userRepo, $request->data->username, $request->data->password));
break;
...
}
...
}
/**
* Verify given username and password.
*
* @param UserRepository $userRepo
* @param string $username
* @param string $password
* @return bool
*/
private function verifyPassword(UserRepository $userRepo, string $username, string $password): bool
{
$user = $userRepo->findOneBy(['email' => $username]);
if ($user == null || $user->getPassword() == null) {
return false;
}
return password_verify($password, $user->getPassword());
}
app.post('/webhooks', webhookMiddleware("webhookUsername", "webhookPassword"), (req, res) => {
// Get the webhook action and act accordingly. Every Corbado
// webhook has an action.
let request;
let response;
switch (webhook.getAction(req)) {
// Handle the "passwordVerify" action which basically checks
// if the given username and password are valid.
case webhook.WEBHOOK_ACTION.PASSWORD_VERIFY: {
request = webhook.getPasswordVerifyRequest(req);
// Now check if the given username and password is
// valid. Implement verifyPassword() function below.
const isValid = verifyPassword(request.data.username, request.data.password)
response = webhook.getPasswordVerifyResponse(isValid);
res.json(response);
break;
}
...
}
});
/**
* Verify given username and password.
*
* !!! MUST BE IMPLEMENTED BY YOU !!!
*
* @param {string} username
* @param {string} password
* @return {boolean}
*/
function verifyPassword(username, password) {
/////////////////////////////////////
// Implement your logic here!
////////////////////////////////////
return false;
}
Please provide a username (email address, phone number) that does NOT exist in your database. This test will check if non-existing users are handled properly.

PHP
Node.js
#[Route('/webhooks', name: 'corbado', methods: 'POST')]
public function corbadoWebhook(UserRepository $userRepo, Request $request, string $webhookUsername, string $webhookPassword): Response
{
// Get the webhook action and act accordingly. Every Corbado
// webhook has an action.
switch ($webhook->getAction()) {
// Handle the "authMethods" action which basically checks
// if a user exists on your side/in your database.
case $webhook::ACTION_AUTH_METHODS:
$request = $webhook->getAuthMethodsRequest();
// Now check if the given user/username exists in your
// database and send status. Implement getUserStatus()
// function below.
$status = $this->userStatus($userRepo, $request->data->username);
$webhook->sendAuthMethodsResponse($status);
break;
...
}
...
}
/**
* Detects user status
*
* @param UserRepository $userRepo
* @param string $username
* @return string
*/
private function userStatus(UserRepository $userRepo, string $username): string
{
$user = $userRepo->findOneBy(['email' => $username]);
// Look up in database if $username exists and if $username is blocked/not permitted to login
if ($user == null) {
return AuthMethodsDataResponse::USER_NOT_EXISTS;
}
if ($user->isBlocked()) {
return AuthMethodsDataResponse::USER_BLOCKED;
}
return AuthMethodsDataResponse::USER_EXISTS;
}
app.post('/webhooks', webhookMiddleware("webhookUsername", "webhookPassword"), (req, res) => {
// Get the webhook action and act accordingly. Every Corbado
// webhook has an action.
let request;
let response;
switch (webhook.getAction(req)) {
...
case webhook.WEBHOOK_ACTION.AUTH_METHODS: {
request = webhook.getAuthMethodsRequest(req);
// Now check if the given user/username exists in your
// database and send status. Implement getUserStatus()
// function below.
const status = getUserStatus(request.data.username);
response = webhook.getAuthMethodsResponse(status);
res.json(response);
break;
}
}
});
/**
* Checks if user exists on your side/in your database.
*
* !!! MUST BE IMPLEMENTED BY YOU !!!
*
* @param {string} username
* @return {string}
*/
function getUserStatus(username) {
/////////////////////////////////////
// Implement your logic here!
////////////////////////////////////
// Example
if (username === '[email protected]') {
return EXISTS;
}
return NOT_EXISTS;
}
Webhook requests from Corbado sent to your backend follow this payload structure:
{
"id": "who-1234567890", // Unique ID per webhook request
"projectID": "pro-1234567890", // Your project ID from the developer panel
"action": "authMethods", // The specific action of the webhook request, see table below
"data": {
// Data object dependent on action
}
}
The action is sent as a header (X-Corbado-Action) as well. This makes it easier for you to unserialize the payload into an action dependent entity / model by taking the action from the header instead of taking it from the payload itself.
Webhook responses from your backend sent to Corbado follow this payload structure:
{
"responseID": "d5a80602-a771-4532-8cc8-6d4a9003d92a", // A response ID you can set in your backend for debugging
"data": {
// Data object dependent on action
}
}
The following webhooks actions exist:
Action | Description |
---|---|
This action returns if the user already exists in the user database and which authentication methods already exist. | |
This action verifies if the provided username and password combination of the existing authentication is valid. |
To make the implementation of the webhook endpoint in your backend as smooth as possible we provide the following libraries on GitHub. Plus, they come with entities / models for request and response (dependent on action) and ease authentication handling for you. We highly encourage you to use them.
Last modified 6d ago