Send Frontend App Events Directly to Slack
- Share:
Introduction
In our dynamic startup environment, we are continually seeking ways to monitor users' engagement with our application. We want to get notify for various user actions, such as new sign-ups, achievement of key milestones, configuration of new resources, or subscribing to premium features. To make these moments more memorable, we have found an effective strategy: directly transmitting these frontend app events to a designated Slack channel, as they happen.
One way of doing so is by using dashboarding and monitoring tools to set alerts on specific events. Our application is heavily invested in the UI experience, and we want to measure these milestones based on user actions in the UI. We already use LogRocket and other observability tools, but haven't found an efficient way to convert events logged there into Slack messages.
This article, will show how we used Slack APIs from our frontend app to send messages to a Slack channel. We will cover the APIs we used, and how we solved the challenge of calling backend APIs from a frontend app. With this article, you'll learn how to call backend-oriented APIs directly from the frontend app using a new open-standard protocol called FoAz.
Slack APIs
Slack is an API-first product with a very rich set of APIs. This means everything that can be done through the UI, can be done using APIs as well. Slack also allows us to build an automated workflow that drives all its cool applications.
We will use the chat.postMessage API, which allows us to post messages to a channel.
Looking at the documentation of the chat.postMessage endpoint, we can see that it requires a token to be sent as part of the request. This token will belong to a special bot we will use to send our event messages.
Our first challenge is that this token cannot be exposed in the frontend app.
The token shouldn't be available for everyone who accesses our browser app, as we don’t want anyone to just grab it and spam our Slack channel.
The second challenge, even if we solve the token store problem, is the token's granularity.
The default option would be to set up a token that allows all users to send messages to the channel. That's not good enough, as we want to restrict access to only the user who triggered the event. For example, if we want to send only admin user events, we don't want regular users to be able to send events.
To solve these challenges, we will use FoAz, a feature in Permit.io that allows us to call backend APIs from the frontend app and define better permissions for "root" level tokens and secrets.
FoAz
Frontend Only Authorization (FoAz) is a standard that combines three components:
A secret vault that keeps our tokens and secrets secure.
A reverse proxy that verifies our application users' identity (authentication) before the backend API calls are triggered.
A policy engine that checks our users have the right permissions to call the backend API.
Using FoAz, we can create Slack API calls directly from the browser.
Let's start to configure our FoAz implementation by opening a free Permit.io account at app.permit.io
Configure Users and Roles
The first step in our FoAz configuration is configuring our application’s users and roles.
Create the following roles in Permit.io dashboard:
admin - This role will allow users to send messages to the Slack channel.
user - This role will allow users to read messages from the Slack channel.
Create the following users in Permit.io:
thor@foaz-events.app
- This user will be assigned to the admin role.someone@foaz-events.app
- This user will be assigned to the user role.
Get the Slack Token
The first step to configure our call is getting the secrets from Slack and storing them in our secret vault. To do that, you'll have to create a Slack app and get the secrets from there. You can find instructions on how to get the secrets from Slack here. Mind that you'll need an app with the chat:write
permission and a bot user to send messages to a channel.
This is an example of our app manifest, so you can paste it on Slack to get a pre-configured app.
{
"display_information": {
"name": "Permit.io (bot)",
"description": "Permit.io Announcement Bot",
"background_color": "#3a2f26"
},
"features": {
"bot_user": {
"display_name": "GreetBot",
"always_online": false
}
},
"oauth_config": {
"scopes": {
"bot": ["chat:write"
]
}
},
"settings": {
"org_deploy_enabled": false,
"socket_mode_enabled": false,
"token_rotation_enabled": false
}
}
Configure the API Call Proxy
Now that we have the secret to call Slack’s APIs, we can configure the API call proxy.
This configuration will add a layer of security between our frontend app and the Slack API, making sure our users are authenticated and authorized to call it.
In the FoAz Proxy page in Permit.io, click Add New Configuration
In the URL field, insert slack.com/api/chat.postMessage
In the method field, choose the
POST
methodTo send the message, map this call to a new resource called Chat (you can do it in the dropdown opened when you click on Resource)
Add an action - let’s call it send.
In the secret field, we should paste the Slack bot secret.
This is how the configuration should look like:
Configure Permissions
With our application roles, actions, and resources configured, we can now configure the permissions for our users. In the Policy Editor screen, let's check only the Admin users to be able to call the Slack API.
Now that we have our FoAz configured, we can start implementing the frontend app that will call the Slack API.
Our Sample Application
To run our code, we created a sample application where we will demonstrate how to call the Slack API from the frontend app. We invite you to do this tutorial interactively while your run the code on your local machine.
Note: To run the application, you'll need a Node.js environment and a Slack app/account.
Run the Application
Clone the sample application
git clone git@github.com:permitio/foaz-slack-example.git
Install the dependencies
npm install
Run the application
npm run dev
Configure Slack Channel ID
To send messages to a specific channel, we need to configure the channel ID in our application.
To grab that ID, right-click on the channel name and select Copy Link from the menu.
The link will look like this: https://permit-io.Slack.com/archives/
C02TVG7RY1X
Copy the link's last part, and paste it to the VITE_SLACK_CHANNEL_ID
constant in the .env file.
To complete the configuration, we also should paste the proxy ID from the FoAz configuration to the file as the VITE_PERMIT_PROXY_ID
variable
The code in the .env file should look like this:
VITE_SLACK_CHANNEL_ID=C05EDEC1F7C
VITE_PERMIT_PROXY_ID=b8d1fd0681b745e2accaa1cdf24c52e1
Test the Application
As you can see in the opened browser window, we need to log in to our application. Our goal is to get Slack messages sent to the events channel when our admin logs in but not when a regular user logs in. Let's try to login with the admin user we created in Permit.io - thor@foaz-events.app
(at this point, we just mock local auth, no password needed). Now when you log in, you suppose to see immediately that we fail to send the event message and we can see an error message 🫤.
Configure JWKs
The reason for the error is that our token cannot be verified by the proxy. To make our token to be verifiable by the proxy, we need to configure the proxy with the JWKs we used to sign the token.
Go to the terminal when you used to run npm run dev, and search for the following log message.
--- Public JWKS --- {"keys":[{"kty":"RSA","kid":"5vXye0jM2MxctISKoq64V2Pb05mXQJQS6QpuhcfLps4","use":"sig","alg":"RS256","e":"AQAB","n":"kmTcV248-bCY7pwwLztRK8sSXXd5PYIq62PIQdLZcVg-ns0F_TfOydKqmZPrDTD_CH0DcKauB3naq79iTGKgj_ded0q5dAKWfRc-2X_sGYYY4Er6esOp4nTx1gPy6WfdZKBdett4YP9cA43sHR96VMOEpQv0cEo9XklmDdcBmcPeCf1Xp2Io_kS8wZMD-uE7ZwwX5Y4skvO3LiXqKUk-OJf0H0GR35D_YrCYYM_5jbUkgXnfM2RStKlVEzBNNUM85PCOyqhH2rb3EA3TvsCdhTyz6sLgPnQ6EN_tRG8CesuvOr3fqxqRBWfiEkwNJ1DwMuw3j2iAaUGLcw69WMdnAw"}]}
In Permit.io UI, go to Settings -> JWKs and add the JWKs from the logs in your relevant environment.
Now, let's try to login again with the admin user. As you can see, we got a success message that we are logged in, and we got a message in our Slack channel.
Test Permissions
As you remember, the other challenge we had was to limit the access to the Slack API to only the admin users. Let's try now to logout and login with the regular user we created in Permit.io - someone@foaz-events.app
- as you can see now, and we got an error message that we are not authorized to call the Slack API.
To see the real magic of FoAz in action, let's go back to the policy editor screen in Permit.io and change the policy to allow the regular user to call the Slack API.
Now, let's try to login again with the regular user. As you can see, we got a success message that we are logged in, and we got a message in our Slack channel.
Summary
In this article, we've learned how easily you can create a simple sending of app events in your application. As a next step, you can wrap the example code with a nice app events framework in your application and do it in a more elegant way.
Want to learn more about permissions and frontend access control?
Read about FoAz in Permit.io and FoAz. If you have any more questions regarding this article or FoAz, you are welcome to join our Slack community.
Written by
Gabriel L. Manor
Full-Stack Software Technical Leader | Security, JavaScript, DevRel, OPA | Writer and Public Speaker