The developer preview for workspace apps has ended. We’re taking the components of workspace apps and bringing them in phases to existing as well as new apps.
You are welcome to install workspace apps as internal integrations or distribute them to other workspaces, but we won't accept them as submissions for the Slack app directory going forward.
OAuth and the Permissions API work just fine for apps wanting to ask for all the permissions up front.
But a workspace app may ask for additional permissions conversationally, progressively adding resources and scope to its capabilities.
Your app's initial moment of installation is just the beginning.
By default, your app is only installed into a single conversation with a single user — the installer.
You can request a list of OAuth scopes as part of an OAuth-based installation process, getting assigned specific scopes and resource combinations by the installer. But it'd be pretty tedious for every user that wants to work with your app to have to also go through this installation flow.
Imagine another user starting a DM with your app and realizing you don't have the permission to examine their profile, or your recently created slash command wasn't yet installed.
To effectively use progressive permissions, your app should make use of the Events API, app events, and either interactive messages or slash commands.
The progressive permissions flow begins with a user interacting with your app.
To ask for an additional permission, a user must first interact with your application one of two ways: 1. Invoke a slash command, if your app offers one 2. Interact with a message button or message menu as part of the interactive message framework.
trigger_id
When that interaction occurs, your slash command request URL or interactive message request URL will receive a standard payload with a bonus field called trigger_id
.
A trigger_id
is produced and delivered when a user interacts with your app. Use it with three seconds of receiving to draw a theoretical dotted line between the interaction and your requesting permissions. Learn more about triggers.
trigger_id
to request upgraded permissionsUsing the apps.permissions.request
method, request any additional OAuth scopes, passing the time-sensitive trigger_id
as a kind of symbolic proof of user interest.
After receiving a successful apps.permissions.request
, Slack will pop open an in-client dialog with the end user, making the case for your upgraded permissions.
Depending on whether they approve or revoke, you'll then receive a set of accompanying Events API events: scope_granted
and resources_granted
if it's successful, or scope_denied
if they turn your request down.
Here are the nuts and bolts of a typical progressive permissions flow:
Your app is installed in a direct message conversation with @izzy. You only have the default permissions and they only apply to your conversation with @izzy.
You want to install a slash command in your app's conversations.
Step 1: Tell @izzy you have a slash command and to install it just click this button by posting an interactive message to your direct message conversation.
We'll send a simple message using chat.postMessage
with a message button attachment delivered like:
POST slack.com/api/chat.postMessage
Authorization: Bearer xoxa-2-token-token-token
Content-type: application/json; charset=utf-8
{
"text": "New feature alert: Try our new slash command to look up all the intersections you've collected.",
"attachments": [
{
"callback_id": "perm_request_1234",
"attachment_type": "default",
"fallback": "Adding this command requires an official Slack client.",
"actions": [
{
"name": "add_commands",
"text": "Add /insectoid command",
"type": "button",
"value": "add"
}
]
}
],
"channel": "D0BH95DLH"
}
Your message will deliver to the "app home" conversation with the user in "channel" D0BH95DLH
.
Step 2: Press the button, get a trigger.
When a user (probably you, if you're following along with this) presses the Add /insectoid command
message button we created, your Action URL will receive a standard message button invocation, including a trigger_id
.
Trigger IDs are pointers to a point of time in a conversation or interaction your app was involved in. They are short-lived and can be used to perform a few different operations. The one we're most concerned with is opening a permission upgrade request dialog with the user.
Here's an example: 11820576016.6048553856.093b9205636ddbfc180e1e74d33e9af6
Step 3: Use apps.permissions.request
to prompt Slack to invoke a modal permissions dialog with the user.
apps.permissions.request
takes three parameters:
token
- your workspace token for the workspace, typical!trigger_id
- the trigger_id
value you only just received from Step 2. It's time-sensitive. Use it context with your moment of conversation.scopes
- a comma-separated list of the scopes you want to add to the app, in this case commands
but could've been users:read,channels:history
or similar.Our request may look something like:
POST https://slack.com/api/apps.permissions.request?token=xoxa-2-token-token-token
trigger_id=11820576016.6048553856.093b9205636ddbfc180e1e74d33e9af6
&scopes=commands
The HTTP response is a simple HTTP 200 with {"ok":true}
if things check out or {"ok":false}
if you don't provide a valid scope or trigger_id
or otherwise can't properly make this request.
Step 4: The user is presented with a dialog in their open Slack client. It's super-friendly. It asks whether this app can upgrade its permissions to include commands
, the ability to use Slash commands. Let's assume the user says yes here.
Step 5: Your Events API request URL receives a small flurry of events (OK, 2):
The first is scope_granted
and it tells you that the commands
scope was added to the installation. It even includes the trigger_id
you just used in case you want to track it roundtrip:
{
"token": "verification_token",
"team_id": "T061EG9R6",
"api_app_id": "A0BLA3EP2",
"event": {
"type": "scope_granted",
"scopes": [
"commands"
],
"trigger_id": "11820576016.6048553856.093b9205636ddbfc180e1e74d33e9af6"
},
"type": "event_callback",
"authed_teams": [],
"event_id": "Ev0BQ5FTL0",
"event_time": 1497911545
}
The second event gets into more detail about the resources involved and where that commands
scope is now applicable to. In the case of commands
, that'll be any channel contexts your app is installed in. Slash commands are used in channels and other conversational contexts.
{
"token": "verification_token",
"team_id": "T061EG9R6",
"api_app_id": "A0BLA3EP2",
"event": {
"type": "resources_added",
"resources": [
{
"resource": {
"type": "im",
"grant": {
"type": "specific",
"resource_id": "D0BH95DLH"
}
},
"scopes": [
"chat:write",
"im:read",
"im:history",
"commands"
]
}
]
},
"type": "event_callback",
"authed_teams": [],
"event_id": "Ev0BLTJ7JM",
"event_time": 1497911545
}
Now @izzy can use /insectoid
in your app-to-user DM conversation and any other channels your app is installed in.