---
title: "Enterprise-managed authorization"
summary: "Enterprise-managed authorization (EMA) is an alternative to the OAuth 2.0 authorization code flow, defined as an extension on top of the Model Context Protocol (MCP). It removes the need for your users to individually authorize your app to access the Slack MCP server."
url: "https://docs.slack.dev/authentication/enterprise-managed-authorization"
type: "guide"
---

Source: https://docs.slack.dev/authentication/enterprise-managed-authorization

# Enterprise-managed authorization

Enterprise-managed authorization (EMA) is an alternative to the [OAuth 2.0 authorization code flow](https://docs.slack.dev/authentication/installing-with-oauth.md), defined as an [extension](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization) on top of the Model Context Protocol (MCP). It removes the need for your users to individually authorize your app to access the Slack MCP server.

Instead, your app can request special tokens ("ID-JAGs") for a user logged in via an identity provider (IdP) like Okta. These ID-JAGs can be passed into the Slack user token endpoint and exchanged for short-lived tokens with which to access the Slack MCP server. Once the user has logged in to the IdP, this process is transparent to them.

## Feature comparison {#feature-comparison}

Behavior

Authorization code flow

Enterprise-managed authorization

Types of tokens

Bot and user tokens for API and MCP server

User tokens for MCP server

How authorization is granted

User reviews scope grants and explicitly authorizes via web form

IdP admins define what permissions are granted to users for each MCP server

App installations

Workspace and organization

Organization only

* * *

## Enabling your app for enterprise-managed authorization {#enabling-your-app}

Update app configuration

For EMA to work with your app, you need to mark it as supported in the app configuration.

Your app can be marked as supporting EMA via the [app settings](https://api.slack.com/apps) in the **OAuth and Permissions** section by toggling it on: ![enterprise-managed authorization app configuration toggle](/assets/images/ema_app_toggle-68d1ff12df3165a2fad1416095acf569.png) or by setting the `is_enterprise_managed_auth_supported` property in the `oauth_config` section of the manifest to `true`.

*   JSON
*   YAML

```
{    …    "oauth_config": {        "is_enterprise_managed_auth_supported": true    },    …}
```

```
…oauth_config:  is_enterprise_managed_auth_supported: true…
```

* * *

## Getting a user token for the MCP server {#getting-a-user-token}

Like the authorization code flow, getting a user token via EMA is a three-step process:

1.  Request an identity credential from the IdP.
2.  Exchange the identity credential for an ID-JAG.
3.  Exchange the ID-JAG for an access token.

![EMA flow diagram](/assets/images/ema_flow-aeb762201457ff3991fd8e7f4df6de5b.png)

### Request an identity credential from the IdP {#request-identity-credential}

You will need to get a credential identifying the user from the IdP. This may either be an OpenID Connect ID token or an OAuth 2.0 refresh token.

If your app supports Single Sign-On (SSO) and a user has signed in using it, you already have a user credential.

*   If the user signed in via OpenID Connect, you already have an OpenID Connect ID token and you can skip to the next section.
*   If the user signed in via SAML 2.0, you will need to exchange the assertion for a refresh token as explained in [Section 4.5 of the Identity Assertion JWT Authorization Grant spec](https://www.ietf.org/archive/id/draft-ietf-oauth-identity-assertion-authz-grant-04.html#section-4.5).

If your app does not support SSO, you will need to add support for providing IdP configurations and logging a user in to a configured IdP. The [User Authentication section of the EMA specification](https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/stable/enterprise-managed-authorization.mdx#3-user-authentication) provides a cursory example of an OpenID Connect exchange. A fuller explanation of how to implement OpenID Connect or SAML 2.0 to get user identity credentials from an IdP is beyond the scope of this doc, but is covered by a number of other guides available online.

### Exchange the identity credential for an ID-JAG {#exchange-identity-credential-for-id-jag}

You now need to exchange the identity token for an ID-JAG (a token that Slack will trust). This is done by making a call to the token endpoint for the IdP's authorization server. If you don't have the token endpoint URL set explicitly as part of IdP configuration, it may be published at the well-known URL for the authorization server; e.g., `https://acme.idp.example/.well-known/oauth-authorization-server`

At a minimum, you'll need to provide the following parameters:

Parameter

Value

`requested_token_type`

`urn:ietf:params:oauth:token-type:id-jag`

`audience`

`https://mcp.slack.com/`

`subject_token`

The identifying credential you acquired in the previous step

`subject_token_type`

One of:

*   `urn:ietf:params:oauth:token-type:id_token` for an OpenID Connect ID token
*   `urn:ietf:params:oauth:token-type:refresh_token` for a refresh token

`grant_type`

`urn:ietf:params:oauth:grant-type:token-exchange`

*   You will likely want to provide a `scope` parameter as well with a space-separated set of scopes that the user is requesting.
*   You will need to provide parameters that identify your app to the IdP; e.g., a `client_id`/`client_secret` pair or a `client_assertion` JWT signed with your private key.

An example request looks like this:

```
POST /oauth2/token HTTP/1.1Host: acme.idp.exampleContent-Type: application/x-www-form-urlencodedgrant_type=urn:ietf:params:oauth:grant-type:token-exchange&requested_token_type=urn:ietf:params:oauth:token-type:id-jag&audience=https://mcp.slack.com/&scope=chat:write+reactions:read&subject_token=eyJraWQiOiJzMTZ0cVNtODhwREo4VGZCXzdrSEtQ...&subject_token_type=urn:ietf:params:oauth:token-type:id_token&client_id=2ec954a1d60620116d36d9ceb7&client_secret=a26d84873504215a34a86d52ef5cd64f4b76
```

If the request succeeds, you will get a JSON response. The `access_token` field contains the ID-JAG. Please do not modify the ID-JAG; Slack will not accept it if it has been altered.

Sample response:

```
{    "issued_token_type": "urn:ietf:params:oauth:token-type:id-jag",    "access_token": "eyJhbGciOiJIUzI1NiIsI...",    "token_type": "N_A",    "scope": "chat:write",    "expires_in": 300}
```

Differing scopes

The scopes on the ID-JAG may not be the ones requested. This is subject to the policies configured at the IdP.

### Exchange the ID-JAG for an access token {#exchange-id-jag-for-access-token}

The last step is the same as in the OAuth 2.0 authorization user-centric code flow: call the [`oauth.v2.user.access`](https://docs.slack.dev/reference/methods/oauth.v2.user.access.md) endpoint. The difference here is that instead of providing a `code` parameter and an `authorization_code` grant type, we provide the ID-JAG as the `assertion` parameter and a `urn:ietf:params:oauth:grant-type:jwt-bearer` grant type. For example:

```
POST /api/oauth.v2.user.access HTTP/1.1Host: slack.comgrant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=eyJhbGciOiJIUzI1NiIsI…&client_id=1234567890.2345678901&client_secret=foobarbaz…
```

If this succeeds, the endpoint will return a JSON response with the access token in the `access_token` property and the issued scopes in the `scope` property.

Example:

```
{    "token_type": "Bearer",    "access_token": "xoxp-foo-bar-…",    "expires_in": 3600,    "scope": "chat:write"}
```

EMA tokens are short-lived

The access tokens retrieved via EMA are short-lived (an hour at the time of writing, though that may change). The identity credential obtained for the user earlier (the OpenID Connect ID token or refresh token) is long-lived. You will need to add support for retrieving new access tokens using the identity credential frequently.

## More information {#more-information}

*   [MCP Enterprise-Managed Authorization information](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization)
*   [Enterprise-Managed Authorization specification](https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/stable/enterprise-managed-authorization.mdx)
*   [Identity Assertion JWT Authorization Grant (ID-JAG) specification](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/)
