From b11dc897ef51dbb55468f7668ef679c3feb673f1 Mon Sep 17 00:00:00 2001 From: Adam Walker <575410+Crashdoom@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:14:22 -0500 Subject: [PATCH 1/2] docs(webhooks): add webhook documentation - Add about webhooks page - Add some webhook events and payloads - Add info on validating payloads and JWTs - Fix spelling error - Fix CSS --- docs/api/endpoints/v0/users.mdx | 2 +- docs/api/webhooks/_category_.json | 4 + docs/api/webhooks/about.md | 9 ++ docs/api/webhooks/events.md | 158 +++++++++++++++++++++++++++ docs/api/webhooks/validating.md | 35 ++++++ src/components/attribute.module.scss | 2 +- 6 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 docs/api/webhooks/_category_.json create mode 100644 docs/api/webhooks/about.md create mode 100644 docs/api/webhooks/events.md create mode 100644 docs/api/webhooks/validating.md diff --git a/docs/api/endpoints/v0/users.mdx b/docs/api/endpoints/v0/users.mdx index 3f0de53..bd47647 100644 --- a/docs/api/endpoints/v0/users.mdx +++ b/docs/api/endpoints/v0/users.mdx @@ -54,7 +54,7 @@ hide_table_of_contents: true The email address of the user. - The preferred name of the user. If provided, this should be used instead of the first and ast name, except where legally required. + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. The first name of the user. diff --git a/docs/api/webhooks/_category_.json b/docs/api/webhooks/_category_.json new file mode 100644 index 0000000..4164b64 --- /dev/null +++ b/docs/api/webhooks/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Webhooks", + "position": 3 +} \ No newline at end of file diff --git a/docs/api/webhooks/about.md b/docs/api/webhooks/about.md new file mode 100644 index 0000000..b289209 --- /dev/null +++ b/docs/api/webhooks/about.md @@ -0,0 +1,9 @@ +# About Webhooks + +Webhooks allow you to set up external applications to receive notifications when certain events happen. When a webhook event is triggered, we'll send a HTTP POST payload to the provided URL for the application. + +These webhook events can be used to trigger automated actions in third-party applications, such as updating access control, mailing lists, and more. + +## Test event + +When you setup a webhook, you can send a test event to verify that the webhook is working correctly by using the **Test** button in Housekeeping. \ No newline at end of file diff --git a/docs/api/webhooks/events.md b/docs/api/webhooks/events.md new file mode 100644 index 0000000..2a5f464 --- /dev/null +++ b/docs/api/webhooks/events.md @@ -0,0 +1,158 @@ +# Events and Payloads + +You can create webhooks that subscribe to one or more events listed on this page. Each webhook event listed here includes a description of the properties and an example payload. + +## Common properties + +Each webhook, in addition to the event-specific properties, will include the following common properties: + + + The name of the event that triggered the webhook. + + + The event-specific data. See the corresponding section under **event types** for more information. + + +## Common headers + +Each POST request will include the following headers: + + + The HTTP client used to send the request. This will always be `ConCat/AxiosHTTPClient`. + + + A bearer token with a signed JWT payload containing a base64-encoded sha256 hash of the `data` property. See [Validating Payloads](/docs/api/webhooks/validating) for more information. + + +## Event types + +### `volunteer-submitted` + +
+

When a user creates a new volunteer application.

+ + The volunteer record containing the user's application. + <> + + The unique identifier of the volunteer application. + + + The preferred method of contact for the volunteer. + + + The contact methods for the volunteer. + <> + + A string representing the type of contact method. + + + An arbitrary string provided by the user for the contact method. + + + + + Whether the volunteer is available before the event. + + + Any additional information the user provided. + + + The user's previous convention experience. + + + The user's previous experience outside of events that may relate to their preferred departments. + + + Any panels or events the user would not want to miss. + + + The date the volunteer application was created. + + + The date the volunteer application was last updated. + + + + + The user who created the volunteer application. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + +
+
+ + {`{ + "event": "volunteer-submitted", + "data": { + "volunteer": { + "id": "1234", + "contactMethod": "email", + "contactMethods": { + "email": "johnny.test@concat.systems", + "discord": "JohnnyTest#1234", + }, + "availableBeforeCon": true, + "anythingElse": "I'm a pretty cool guy.", + "previousConExperience": "I've been to a few conventions.", + "previousOtherExperience": "I've worked at a few conventions.", + "eventsCanNotMiss": "I really want to see the panel on how to make a better sandwich.", + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "user": { + "id": "1234", + "username": "JohnnyTest", + "firstName": "Johnny", + "preferredName": "Johnny", + "lastName": "Test", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + } + } +}`} + +
+
+ +### `volunteer-updated` + +### `volunteer-assigned` + +### `volunteer-unassigned` + +### `volunteer-deleted` + +### `registration-created` + +### `registration-updated` + +### `user-updated` \ No newline at end of file diff --git a/docs/api/webhooks/validating.md b/docs/api/webhooks/validating.md new file mode 100644 index 0000000..7be924f --- /dev/null +++ b/docs/api/webhooks/validating.md @@ -0,0 +1,35 @@ +# Validating Payloads + +Each webhook POST request will include a signed JWT payload in the `authorization` header. The payload contains a Base64 **sha256** hash of the `data` property. You can use this hash to verify that the payload was sent by ConCat. + +## JWT format + +The JWT payload will contain the following properties: + +| Key | Description | +| --- | ----------- | +| `int` | The SHA256 hash of the `data` property. | +| `exp` | The expiration time of the JWT payload. JWT events are valid for 120 seconds from creation. | +| `iat` | The time the JWT payload was created. | +| `aud` | The URL of the webhook. | +| `iss` | Always `concat.app`. | +| `sub` | Always `webhook`. | + +## Verifying the JWT + +We **strongly** recommend verifying the JWT payload before processing the webhook event. At a minimum, you should verify the following: + + * The `aud` property matches the URL of the webhook. + * The `exp` property is greater than the current time. + * The `iss` property is `concat.app`. + * The `sub` property is `webhook`. + +### Verifiying the JWT signature + +The JWT payload will be signed by ConCat and can be validated with the public key found at the `/api/webhooks/key` endpoint of your ConCat instance. The public key is a PEM-encoded X.509 RSA public key. + +We recommend using one of the supported JWT libraries listed on the [jwt.io](https://jwt.io/libraries) website. + +## Verifying the payload hash + +The `int` property of the JWT payload is a Base64-encoded SHA256 hash of the `data` property of the webhook payload. You can use this hash to verify that the payload was not modified by a third-party or damaged in transit. \ No newline at end of file diff --git a/src/components/attribute.module.scss b/src/components/attribute.module.scss index 691c6e1..98ecec2 100644 --- a/src/components/attribute.module.scss +++ b/src/components/attribute.module.scss @@ -1,7 +1,7 @@ .attribute, .attribute-parent { margin-top: 0.5rem; padding-bottom: 0.5rem; - margin-left: 1.3rem; + margin-left: 1rem; } .attribute { From a5e4528f75f105abf9868276c28b16ebc5f21241 Mon Sep 17 00:00:00 2001 From: Adam Walker <575410+Crashdoom@users.noreply.github.com> Date: Thu, 25 Aug 2022 11:27:11 -0500 Subject: [PATCH 2/2] docs(webhooks): finish documentation - Add additional event types - Fix formatting issues --- docs/api/webhooks/events.md | 700 +++++++++++++++++++++++++++++++++++- 1 file changed, 694 insertions(+), 6 deletions(-) diff --git a/docs/api/webhooks/events.md b/docs/api/webhooks/events.md index 2a5f464..c9f9f80 100644 --- a/docs/api/webhooks/events.md +++ b/docs/api/webhooks/events.md @@ -10,7 +10,7 @@ Each webhook, in addition to the event-specific properties, will include the fol The name of the event that triggered the webhook.
- The event-specific data. See the corresponding section under **event types** for more information. + The event-specific data. See the corresponding section under event types for more information. ## Common headers @@ -18,10 +18,10 @@ Each webhook, in addition to the event-specific properties, will include the fol Each POST request will include the following headers: - The HTTP client used to send the request. This will always be `ConCat/AxiosHTTPClient`. + The HTTP client used to send the request. This will always be ConCat/AxiosHTTPClient. - A bearer token with a signed JWT payload containing a base64-encoded sha256 hash of the `data` property. See [Validating Payloads](/docs/api/webhooks/validating) for more information. + A bearer token with a signed JWT payload containing a base64-encoded sha256 hash of the data property. See Validating Payloads for more information. ## Event types @@ -144,15 +144,703 @@ Each POST request will include the following headers: ### `volunteer-updated` + +
+

When an existing volunteer application is updated.

+ + The volunteer record containing the user's application. + <> + + The unique identifier of the volunteer application. + + + The preferred method of contact for the volunteer. + + + The contact methods for the volunteer. + <> + + A string representing the type of contact method. + + + An arbitrary string provided by the user for the contact method. + + + + + Whether the volunteer is available before the event. + + + Any additional information the user provided. + + + The user's previous convention experience. + + + The user's previous experience outside of events that may relate to their preferred departments. + + + Any panels or events the user would not want to miss. + + + The date the volunteer application was created. + + + The date the volunteer application was last updated. + + + + + The user who created the volunteer application. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + +
+
+ + {`{ + "event": "volunteer-updated", + "data": { + "volunteer": { + "id": "1234", + "contactMethod": "email", + "contactMethods": { + "email": "johnny.test@concat.systems", + "discord": "JohnnyTest#1234", + }, + "availableBeforeCon": true, + "anythingElse": "I'm a pretty cool guy.", + "previousConExperience": "I've been to a few conventions.", + "previousOtherExperience": "I've worked at a few conventions.", + "eventsCanNotMiss": "I really want to see the panel on how to make a better sandwich.", + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "user": { + "id": "1234", + "username": "JohnnyTest", + "firstName": "Johnny", + "preferredName": "Johnny", + "lastName": "Test", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + } + } +}`} + +
+
### `volunteer-assigned` + +
+

When a volunteer is assigned to a department.

+ + The volunteer record containing the user's application. + <> + + The unique identifier of the volunteer application. + + + The preferred method of contact for the volunteer. + + + The contact methods for the volunteer. + <> + + A string representing the type of contact method. + + + An arbitrary string provided by the user for the contact method. + + + + + Whether the volunteer is available before the event. + + + Any additional information the user provided. + + + The user's previous convention experience. + + + The user's previous experience outside of events that may relate to their preferred departments. + + + Any panels or events the user would not want to miss. + + + The date the volunteer application was created. + + + The date the volunteer application was last updated. + + + + + The user who created the volunteer application. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + + + The department the volunteer was assigned to. + <> + + The unique identifier of the department. + + + The name of the department. + + + The email address for contacting the department lead. + + + Whether the department is publicly visible. + + + The date the department was created. + + + The date the department was last updated. + + + +
+
+ + {`{ + "event": "volunteer-assigned", + "data": { + "volunteer": { + "id": "1234", + "contactMethod": "email", + "contactMethods": { + "email": "johnny.test@concat.systems", + "discord": "JohnnyTest#1234", + }, + "availableBeforeCon": true, + "anythingElse": "I'm a pretty cool guy.", + "previousConExperience": "I've been to a few conventions.", + "previousOtherExperience": "I've worked at a few conventions.", + "eventsCanNotMiss": "I really want to see the panel on how to make a better sandwich.", + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "user": { + "id": "1234", + "username": "JohnnyTest", + "firstName": "Johnny", + "preferredName": "Johnny", + "lastName": "Test", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "department": { + "id": "1234", + "name": "Registration", + "email": "registration@concat.event", + "publiclyVisible": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + } + } +}`} + +
+
### `volunteer-unassigned` + +
+

When a volunteer is removed from a department.

+ + The volunteer record containing the user's application. + <> + + The unique identifier of the volunteer application. + + + The preferred method of contact for the volunteer. + + + The contact methods for the volunteer. + <> + + A string representing the type of contact method. + + + An arbitrary string provided by the user for the contact method. + + + + + Whether the volunteer is available before the event. + + + Any additional information the user provided. + + + The user's previous convention experience. + + + The user's previous experience outside of events that may relate to their preferred departments. + + + Any panels or events the user would not want to miss. + + + The date the volunteer application was created. + + + The date the volunteer application was last updated. + + + + + The user who created the volunteer application. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + + + The department the volunteer was removed from. + <> + + The unique identifier of the department. + + + The name of the department. + + + The email address for contacting the department lead. + + + Whether the department is publicly visible. + + + The date the department was created. + + + The date the department was last updated. + + + +
+
+ + {`{ + "event": "volunteer-unassigned", + "data": { + "volunteer": { + "id": "1234", + "contactMethod": "email", + "contactMethods": { + "email": "johnny.test@concat.systems", + "discord": "JohnnyTest#1234", + }, + "availableBeforeCon": true, + "anythingElse": "I'm a pretty cool guy.", + "previousConExperience": "I've been to a few conventions.", + "previousOtherExperience": "I've worked at a few conventions.", + "eventsCanNotMiss": "I really want to see the panel on how to make a better sandwich.", + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "user": { + "id": "1234", + "username": "JohnnyTest", + "firstName": "Johnny", + "preferredName": "Johnny", + "lastName": "Test", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "department": { + "id": "1234", + "name": "Registration", + "email": "registration@concat.event", + "publiclyVisible": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + } + } +}`} + +
+
### `volunteer-deleted` - -### `registration-created` + +
+

When a volunteer has their volunteer application deleted.

+ + The volunteer record containing the user's application. + <> + + The unique identifier of the volunteer application. + + + The preferred method of contact for the volunteer. + + + The contact methods for the volunteer. + <> + + A string representing the type of contact method. + + + An arbitrary string provided by the user for the contact method. + + + + + Whether the volunteer is available before the event. + + + Any additional information the user provided. + + + The user's previous convention experience. + + + The user's previous experience outside of events that may relate to their preferred departments. + + + Any panels or events the user would not want to miss. + + + The date the volunteer application was created. + + + The date the volunteer application was last updated. + + + + + The user who created the volunteer application. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + + + The department the volunteer was assigned to. + <> + + The unique identifier of the department. + + + The name of the department. + + + The email address for contacting the department lead. + + + Whether the department is publicly visible. + + + The date the department was created. + + + The date the department was last updated. + + + +
+
+ + {`{ + "event": "volunteer-deleted", + "data": { + "volunteer": { + "id": "1234" + } + } +}`} + +
+
### `registration-updated` + +
+

The user created or updated their attendee registration.

+ + The registration record containing the user's event registration. + <> + + The unique identifier of the attendance type product. + + + The unique identifier for the user's chosen badge art. + + + The user's chosen badge name. + + + The unique identifier of the registration. + + + The unique identifier of the user. + + + The date the registration was created. + + + The date the registration was last updated. + + + + + The user who created the registration. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + The social accounts the user has linked to their user profile. + <> + + The name of the social account (e.g. "twitter" or "discord"). + + + The unique identifier of the social account (e.g. "1234" or "JohnnyTest#1234"), with the format depending on the third-party service. + + + + + +
+
+ + {`{ + "event": "registration-updated", + "data": { + "registration": { + "attendanceTypeId": "91011", + "badgeArtId": 12, + "badgeName": "Test User", + "id": "1234", + "userId": "5678", + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z" + }, + "user": { + "id": "5678", + "username": "JohnnyTest", + "firstName": "Johnny", + "lastName": "Test", + "preferredName": "Johnny", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z", + "socialLinks": { + "twitter": "1234", + "discord": "JohnnyTest#1234" + } + } + } +}`} + +
+
-### `user-updated` \ No newline at end of file +### `user-updated` + +
+

The user's profile was created or updated.

+ + The user's profile. + <> + + The unique identifier of the user. + + + The username of the user. + + + The first name of the user. + + + The preferred name of the user. If provided, this should be used instead of the first and last name, except where legally required. + + + The last name of the user. + + + The email address of the user. + + + Whether the user's email address has been verified. + + + The date the user was created. + + + The date the user was last updated. + + + A unique identifier for the organization the user account belongs to. This is used to share a single account across all events run by the same organization. + + + +
+
+ + {`{ + "event": "registration-updated", + "data": { + "user": { + "id": "5678", + "username": "JohnnyTest", + "firstName": "Johnny", + "lastName": "Test", + "preferredName": "Johnny", + "email": "johnny.test@concat.systems", + "verified": true, + "createdAt": "2020-01-01T00:00:00.000Z", + "updatedAt": "2020-01-01T00:00:00.000Z", + "organizationId": "e9eb88a2-6b61-4feb-bbd7-744a05f4ace6" + } + } +}`} + +
+
\ No newline at end of file