Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Build a Slack app with SlackKit
Knock profile imageJeff Everhart
Jeff Everhart forKnock

Posted on • Originally published atknock.app

     

Build a Slack app with SlackKit

If you’re looking for ways to provide value to your app’s users, a Slack integration is worth building . But adding Slack support to an existing app has historically been a large engineering task: you need to mapyour app’s data model onto Slack’s users and channels, provide a wayto authenticate and store credentials, manage notification templates in domain-specific formats likemrkdwn andBlock Kit, and then create UI to handle the self-serve aspects of this process.

SlackKit is a library of drop-in components powered by theKnockSlackProvider, and it uses components like theSlackAuthButton andSlackChannelsCombobox. Engineering teams can add support for Slack channel notifications in Knock in hours, not days or weeks.

In this post, we'll take a high-level look at SlackKit in action and walk through an example Next.js application that implements it.

Getting started

For this project, there are quite a few configuration variables you need before you can get started. Some of these are typical environment variables you would supply to your application, like API keys, tokens, or client ids.

The other set of values would typically be determined by your product's business logic, but you can hardcode these values for the time being.

You can access therepository for this project directly or clone it to your local machine using the following command:

git clone https://github.com/knocklabs/slack-kit-example.git
Enter fullscreen modeExit fullscreen mode

Video walkthrough

If you prefer to learn with video, watch it here.

Setting up a Slack app

You can either follow the setup steps outlined here, or use the official instruction in theSlackKit docs.

Create a new app

First, visithttps://api.slack.com/apps and sign into your account. Then, clickCreate an App and select theFrom scratch option. Next, select which workspace to develop it in. You'll still be able to use it in other workspaces, so this selection isn't critical.

create new app

Add bot features

UnderAdd features and functionality selectBots features. Then, underOAuth and Permissions, give it thechannels:read scope. It doesn’t need any scopes here since we’ll be sending the scopes we need from the component, but we need to do this so we can expose the redirect url form.

create Slack scopes

Add redirect URL

UnderOAuth and Permissions, find the redirect URL section and add this Knock URL to that field:https://api.knock.app/providers/slack/authenticate. Knock's API endpoint will handle the OAuth callback for you and store a Slack access token. Finally, UnderManage distribution, allow it to be publicly distributed.

save redirect urls

Setting up Knock

For this tutorial, you'll need a Knock account. If you don't already have one, you cansign up on this page. You can also find these steps outlined in the officialSlackKit docs.

Create a Slack channel

Adda Slack channel in Knock with theClient Id andClient Secret from theBasic Info section of your Slack. Take note of this channel id for use in the next step.

create slack channel

Create a new workflow

Create a newworkflow with aSlack channel step pointing to this Slack channel. Take note of this workflow key for use in the following steps, and the example project uses a default workflow key ofnew-issue. In themessage template use the following liquid tag to send messages:A new issue was submitted: {{message}}

create new workflow

Environment variables

All of these values are sourced from environment variables at runtime. The example app will check for these values as the first step. Make a copy of.env.sample using the following command:cp .env.sample .env.local

NEXT_PUBLIC_KNOCK_SLACK_CHANNEL_ID

This value comes from Knock after you create a Slack channel in the dashboard.

NEXT_PUBLIC_SLACK_CLIENT_ID

This value comes from Slack when you create a new Slack app. You can find it in your app's "Basic Info" section.

KNOCK_SIGNING_KEY

This value comes from Knock and is used to sign a JWT on behalf of a user to store channel data for Slack tokens and channel ids. You can generate a signing key under "Developers" > "API keys."This is a secret value and should not be exposed publicly.

KNOCK_API_KEY

This value comes from Knock and is used to authenticate server-side API requests. You can find it listed as the secret key under "Developers" > "API keys."This is a secret value and should not be exposed publicly.

NEXT_PUBLIC_KNOCK_CLIENT_ID

This value comes from Knock and is used to authenticate public API requests from the browser. You can find it listed as the public key under "Developers" > "API keys."

NEXT_PUBLIC_KNOCK_API_URL

This value comes from Knock and is used to construct the URL for API endpoints. You can keep the default value for this.

NEXT_PUBLIC_REDIRECT_URL

This value comes from your application. It is where Knock will redirect your user after the OAuth flow with Slack. The default ofhttp://localhost:3000 is valid when running this project locally.

Knock resource variables

To make the connection between Slack channels and Knock objects, you'll also need to provide details for several types of resources in Knock. To do this, you can replace the values in thegetAppDetails function inside of the/app/lib/app-details.ts file. These values would typically be determined by your application's business logic, but we can hardcode them for this example:

exportfunctiongetAppDetails(){return{tenant:"knock-projects",collection:"repositories",objectId:"repo-2",userId:"123",workflowKey:"new-issue",};}
Enter fullscreen modeExit fullscreen mode

You should already have a value forworkflowKey from a previous step, and you can choose auser identifier to use from the dashboard.

Create a tenant

In SlackKit,tenants are used to store the access token for an organization's Slack workspace. You can create a new tenant from the dashboard and include its ID as the value for thetenant property in thegetAppDetails function. You can also use this cURL command to create a tenant by replacing the values fortenant-id,KNOCK_API_KEY, andtenant-name:

curl--location--request PUT'https://api.knock.app/v1/tenants/<tenant-id>'\--header'Content-Type: application/json'\--header'Authorization: Bearer <KNOCK_API_KEY>'\--data'{  "name": "<tenant-name>",}'
Enter fullscreen modeExit fullscreen mode

You doNOT have to create your tenant before using SlackKit. If you pass a tenant ID into theKnockSlackProvider that doesn't exist, SlackKit will create it for you on completion of the OAuth process. However, tenants are an important concept in Knock so we'd recommend reading about thesekey concepts in the SlackKit overview.

Create an object

In SlackKit,objects are used to store channels and act as the recipient of your workflows. You can't create a new object from the dashboard, so you can use this cURL command to create an object by replacing the values forobject-collection,object-id,KNOCK_API_KEY, andobject-name:

curl--location--request PUT'https://api.knock.app/v1/objects/<object-collection>/<object-id>'\--header'Content-Type: application/json'\--header'Authorization: Bearer <KNOCK_API_KEY>'\--data'{    "name": "<object-name>"}'
Enter fullscreen modeExit fullscreen mode

Once you've done that, update the values in thegetAppDetails function to point to your new object.

You doNOT have to create your object before using SlackKit. If you pass an object ID into theSlackChannelsCombobox that doesn't exist, SlackKit will create it for you on the completion when the user registers a channel. However, objects are an important concept in Knock so we'd recommend reading about thesekey concepts in the SlackKit overview.

Running the app locally

Now that you have all of the configuration out of the way, you can install your dependencies using one of the following commands:

npminstall#oryarninstall
Enter fullscreen modeExit fullscreen mode

After your dependencies have installed, you can run the app in dev mode:

npm run dev#oryarn dev
Enter fullscreen modeExit fullscreen mode

If you open the app in a browser athttp://localhost:3000 you should see a screen that looks like this:

confirm env vars

This step gives you an opportunity to confirm that you have all of the necessary environment variables needed to use the application.

If you clickNext you'll navigate to a screen where you can confirm the Knock resources you'll use to connect your Slack app:

confirm knock resources

If all of the values in this step look good, you can clickNext to authenticate with your Slack app and store theaccess_token in Knock.

Sharing Knock and Slack state

Before we dig into the actual SlackKit UI components and their functionality, let's look at how we share certain values across those components in our application.

In the@knocklabs/react package, Knock already exposes aKnockProvider component that is meant to provide top-level authentication and authorization to components farther down in the component tree.

With the SlackKit release, the@knocklabs/react package now also contains a Slack-specific provider, calledKnockSlackProvider. Since these both rely on React context, they are implemented as client-side components in/app/components/providers.tsx in the following manner:

"use client";import{KnockProvider,KnockSlackProvider}from"@knocklabs/react";exportdefaultfunctionProviders({userToken,knockUserId,tenant,children,}:{userToken:string;knockUserId:string;tenant:string;children:JSX.Element;}){return(<><KnockProviderapiKey={process.env.NEXT_PUBLIC_KNOCK_CLIENT_ID!}userId={knockUserId}host={process.env.NEXT_PUBLIC_KNOCK_API_URL}userToken={userToken}>{/*        The KnockProvider handles authentication with Knock, while the KnockSlackProvider        provides shared context to all Slack-related components.        Both are required for Slack-related apps.        */}<KnockSlackProviderknockSlackChannelId={process.env.NEXT_PUBLIC_KNOCK_SLACK_CHANNEL_ID!}tenant={tenant}>{children}</KnockSlackProvider></KnockProvider></>);}
Enter fullscreen modeExit fullscreen mode

To create some of the necessary authentication data, likeuserToken anduserId, we implement theProviders component inside of the rootlayout.tsx file. In this code, which runs on the server, we also add some additional grants to theuserToken JWT to allow the user to interact with the Slack resources stored in Knock. You can read more about theseresource access grants in the docs.

Note 🚨: this is necessary because the user in this context is an end user in
your application who does not have access to Knock as amember of the
account
.
Therefore, these grants provide them elevated privileges to operate on
specific resources using the API.

import{Knock}from"@knocklabs/node";import{Grants}from"@knocklabs/node/dist/src/common/userTokens";import"@knocklabs/react/dist/index.css";importProvidersfrom"./components/providers";import"./global.css";import{getAppDetails}from"./lib/app-details";const{userId,tenant,collection,objectId}=getAppDetails();constsigningKey=process.env.KNOCK_SIGNING_KEY!;asyncfunctionMyApp({children}:{children:React.ReactElement}){//Generate a production build in CI/CD even if we're missing the env varsconstuserToken=signingKey?awaitKnock.signUserToken(userId,{grants:[Knock.buildUserTokenGrant({type:"tenant",id:tenant},[Grants.SlackChannelsRead,]),Knock.buildUserTokenGrant({type:"object",id:objectId,collection:collection},[Grants.ChannelDataRead,Grants.ChannelDataWrite]),],}):"secretOrPrivateKey";return(<><html><bodyclassName="px-12 py-6"><h1className="text-2xl font-bold mb-6">SlackKitDemoApp</h1><ProvidersuserToken={userToken}knockUserId={userId}tenant={tenant}>{children}</Providers></body></html></>);}exportdefaultMyApp;
Enter fullscreen modeExit fullscreen mode

Authenticating with Slack

On this screen, you can initiate the OAuth flow with Slack. This page uses two SlackKit components to help facilitate this interaction:SlackAuthButton andSlackAuthContainer.

initiate oauth flow

Both of these components are client-side components. TheSlackAuthButton component takes yourredirectUrl andslackClientId as props:

<SlackAuthContaineractionButton={<SlackAuthButtonslackClientId={process.env.NEXT_PUBLIC_SLACK_CLIENT_ID!}redirectUrl={process.env.NEXT_PUBLIC_REDIRECT_URL}onAuthenticationComplete={onAuthComplete}/>}/>
Enter fullscreen modeExit fullscreen mode

When this button is clicked, it will initiate an OAuth flow in a pop-up window where the user can authenticate with Slack and choose a workspace to install the app. Once the flow is complete, the pop-up window should close and the state of the component should update to show it isConnected to Slack. Behind the scenes, Knock handles the OAuth callback from Slack and stores anaccess_token on thetenant you provided to theKnockSlackProvider aschannel data.

Note 🚨: if the pop-up window does not close, double check that the
redirectUrl matches your current environment.

From here, you can clickNext to choose one or more Slack channels to associate with your object recipient.

Choosing Slack channels

On this route, you can associate your Knock object recipient with one or more Slack channels using theSlackChannelCombobox component. It accepts aslackChannelsRecipientObject as a prop that specifies acollection andobjectId for the recipient object:

"use client";import{SlackChannelCombobox}from"@knocklabs/react";exportdefaultfunctionSlackChannelWrapper({collection,objectId,className,}:{collection:string,objectId:string,className:string,}){constslackChannelsRecipientObject={objectId:objectId,collection:collection,};return(<divclassName={className}><SlackChannelComboboxslackChannelsRecipientObject={slackChannelsRecipientObject}/></div>);}
Enter fullscreen modeExit fullscreen mode

As you select channels using the combobox input, the component will update the channel data for that object to store the Slack channel ids.

choosing slack channels

Note 🚨: if you want to use a private Slack channel, you need to make sure that
the Slack Bot has been invited to that channel.

At this point, Knock has all of the information it needs to send Slack messages to your selected channels. ClickNext to examine the channel data for your object and tenant.

Examine channel data

In this step, you're not required to take any action, but this page uses the Node SDK to pull channel data for your object recipient and tenant. This will give you an idea of how Knock is storing the data and how these two abstractions interact.

This data is pulled dynamically, so if you make different channel selections or disconnect and reconnect your Slack auth, the value foraccess_token andconnections.channelIds will change as well.

If you clickNext you can test your workflow end-to-end.

Trigger your workflow

In this step, you can see a code sample using the Node SDK of how you'd trigger your workflow. This is actually the code that runs in a server action when you submit the form on this page. Go ahead and submit a form to send a Slack message into your designated channels:

a form to trigger our workflow

Wrapping up

If you need help implementing any of the code in this example app, consider joining ourSlack community. We've got over 500 other developers learning how to improve their notification experiences with Knock.

Thanks for reading and Knock on 🤘

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

The most powerful notification system you'll never build.

Effortlessly send cross-channel notifications to your customers, with advanced functionality like batching, digesting, and delays. Built for developers.

More fromKnock

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp