Webex Messaging
Integrations and Authorization
Add features from third-party services to Webex or perform actions on behalf of another user with Integrations.
anchorWhat Are Integrations?
anchorIntegrations are how you request permission to invoke the Webex REST API on behalf of another Webex user. To do this in a secure way the API supports the OAuth 2 standard which allows third-party integrations to get a temporary access token for authenticating API calls instead of asking users for their password.
If you're sure that your integrations require authenticating on behalf of another Webex user, read on, we'll get you there in a few easy steps:
- Register your integration with Webex
- Request permission using an OAuth Grant Flow
- Exchange the resulting authorization code for an access token
- Use the access token to make your API calls
anchorRegistering Your Integration
anchorRegistering an integration with Webex is super easy. If you're logged in, select My Webex Apps from the menu under your avatar at the top of this page, click "Create a New App" then "Create an Integration" to start the wizard. You'll need to provide some basic information like your integration's name, description, and logo. This information should be user-facing since that's what they'll see in the permission dialog.
After successful registration you'll be taken to a different screen containing your integration's newly created clientID and clientSecret. The Client Secret will only be shown once so please copy and keep it safe!
Each Webex user account is limited to 20 integrations.
anchorScopes
anchorScopes define the level of access that your integration requires. The following is a complete list of scopes and their user-facing descriptions as shown in the permission dialog.
spark-admin:events_readspark-compliance:events_readspark-admin:messages_writespark-compliance:messages_writespark-admin:messages_readspark-compliance:messages_readspark-compliance:recordings_writespark-compliance:recordings_readspark-compliance:memberships_writespark-compliance:memberships_readspark-compliance:meetings_writespark-compliance:meetings_readspark-compliance:rooms_writespark-compliance:rooms_readspark-compliance:teams_readspark-compliance:team_memberships_writespark-compliance:team_memberships_readspark-compliance:webhooks_writespark-compliance:webhooks_readaudit:events_readspark-admin:recordings_writespark-admin:recordings_readspark-admin:reports_writespark-admin:reports_readspark-admin:broadworks_subscribers_writespark-admin:broadworks_subscribers_readspark-admin:broadworks_enterprises_writespark-admin:broadworks_enterprises_readspark-admin:wholesale_billing_reports_writespark-admin:wholesale_billing_reports_readspark-admin:wholesale_sub_partners_writespark-admin:wholesale_sub_partners_readspark-admin:wholesale_customers_writespark-admin:wholesale_customers_readspark-admin:wholesale_subscribers_writespark-admin:wholesale_subscribers_readspark-admin:people_writespark-admin:people_readspark-admin:licenses_readspark-admin:roles_readspark-admin:telephony_config_writespark-admin:telephony_config_readspark-admin:telephony_pstn_writespark-admin:telephony_pstn_readspark-admin:workspaces_readspark-admin:workspace_locations_writespark-admin:workspace_locations_readspark-admin:workspace_metrics_readspark-admin:places_writespark-admin:places_readspark-admin:locations_writespark-admin:locations_readspark-admin:devices_writespark-admin:devices_readspark-admin:organizations_readspark-admin:resource_groups_readidentity:contacts_readspark-admin:resource_group_memberships_writespark-admin:resource_group_memberships_readspark-admin:call_qualities_readspark-admin:hybrid_clusters_readspark-admin:hybrid_connectors_readidentity:tokens_writeidentity:tokens_readidentity:groups_rwidentity:groups_readidentity:organizations_rwidentity:organizations_readidentity:contacts_rwIdentity:one_time_passwordidentity:placeonetimepassword_createcjp:configcjp:config_writecjp:config_readcjp:usermeeting:admin_recordings_writemeeting:admin_recordings_readmeeting:admin_transcripts_readmeeting:admin_participants_readmeeting:admin_schedule_writemeeting:admin_schedule_readmeeting:admin_preferences_writemeeting:admin_preferences_readmeeting:admin_config_writemeeting:admin_config_readmeeting:recordings_writemeeting:recordings_readmeeting:transcripts_readmeeting:controls_writemeeting:controls_readmeeting:participants_writemeeting:participants_readmeeting:schedules_writemeeting:schedules_readmeeting:preferences_writemeeting:preferences_readspark:recordings_writespark:recordings_readspark:allspark:applications_tokenspark:messages_writespark:messages_readspark:memberships_writespark:memberships_readspark:xsispark:xapi_statusesspark:xapi_commandsspark:calls_writespark:calls_readspark:webrtc_callingspark:people_readspark:rooms_writespark:rooms_readspark:teams_writespark:teams_readspark:team_memberships_writespark:team_memberships_readspark:devices_writespark:devices_readspark:telephony_config_writespark:telephony_config_readspark:places_writespark:places_readspark:organizations_readapplication:webhooks_writeapplication:webhooks_readwxc-dedicateduc:admin_perfmon_readguest-issuer:readguest-issuer:writecjds:admin_org_readcjds:admin_org_writecloud-contact-center:pod_convspark-admin:datasource_readspark-admin:datasource_writespark-admin:metrics_readguest-meeting:rwScopes that begin with spark-admin can only be used by users with administrative access to an organization. Requesting these scopes during a grant flow will not give non-admin users access to administrative functions.
The spark-compliance scopes can only be used by an organization's compliance officers. See the Compliance Guide for more information.
The spark:all scope grants access to certain Webex account features that are not granted via the other user-level scopes. Applications which use the Webex SDKs for calling features may require this scope. Most other applications will not need to use this scope. Consult the SDK documentation for information about whether your application will need to use this scope.
As a general best practice, your integration should request only the scope, or scopes, it needs. For example, if you are creating an integration that notifies users of updates in a third-party service, and never responds to any commands, we recommend using only the spark:messages_write scope.
KMS Scope
After registering an integration, it will include the scopes you selected along with an additional scope: spark:kms. This scope is required to give your integration permission to interact with encrypted content (such as messages). For convenience, the scope is included in the integrations's scope list in the example OAuth Authorization URL on the integration's application detail page. If you don't use the example URL, be sure to include the scope when creating authorization URLs for your integration.
State
The state parameter is used to verify that the response from grant flow has not been tampered with along the way. It is recommended that your integration set this to a value that is verifiable once the user gives permission and the web browser is sent to your redirect_uri. A second use for this parameter is to encode basic state information like an internal user ID or the URL of the last page they were on before entering the grant flow.
anchorGetting an Access Token
anchorIf the user granted permission to your integration, the Webex REST API will redirect the user's web browser to the redirect_uri you specified when entering the grant flow. The request to the redirect URL will contain a code parameter in the query string like so:
http://your-server.com/auth?code=YjAzYzgyNDYtZTE3YS00OWZkLTg2YTgtNDc3Zjg4YzFiZDlkNTRlN2FhMjMtYzUz
Your integration will then need to exchange this authorization code for an access token that can be used to invoke the APIs. To do this your app will need to perform an HTTP POST to the following URL with a standard set of OAuth parameters in the body of the POST request. This endpoint will only accept a message body encoded with the application/x-www-form-urlencoded content type.
https://webexapis.com/v1/access_token
The required parameters are:
| Parameter | Value |
|---|---|
grant_type | This should be set to "authorization_code". |
client_id | Issued when creating your integration. |
client_secret | Remember this guy? You kept it safe somewhere when creating your integration. |
code | The authorization code from the previous step. |
redirect_uri | Must match the one used in the previous step. |
An example curl request for sending form data would look like below.
curl -X POST https://webexapis.com/v1/access_token -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&client_id=Cda0958&client_secret=11db688edb1fafb0a13e&code=OTQ5NzA0ZmUtZzU2Zi00NGJkLTliNWYtZmU0NDlhN2Y0Y2I4ZWRhNDQ3NmItMWIx_PF84_ce861fba-6e2f-49f9-9a84-b354008fac9e&state=set_state_here&redirect_uri=http://localhost:8081/authorization-code'
The Webex REST API will then respond with JSON containing an access token and a refresh token, as shown in the example below. Expiration times are provided in seconds:
{
"access_token":"YmVmODgxPF84_ce861fba-6e2f-49f9-9a84-b354008fac9e",
"expires_in":1209599,
"refresh_token":"YjJhMWQiOGI1MGMw_PF84_ce861fba-6e2f-49f9-9a84-b354008fac9e",
"refresh_token_expires_in":7775999,
"token_type":"Bearer",
"scope":"spark:all spark:kms"
}
After the access token expires, using it to make a request from the API will result in an HTTP 401 "Invalid Token Error" response, such as:
{
"message": "The request requires a valid access token set in the Authorization request header.",
"errors": [
{
"description": "The request requires a valid access token set in the Authorization request header."
}
],
"trackingId": "API_12345678-90AB-CDEF-1234-567890ABCDEF"
}
At this point, you should use the refresh token to generate a new access token from the authorization server.
anchorUsing the Refresh Token
anchorUsing access tokens that are short-lived and requiring that they periodically be refreshed helps to keep data secure. If the access token is ever compromised, the attacker will have a limited time in which to use it. If a refresh token is compromised, it is useless to the attacker because the client ID and secret are also required to obtain a new access token.
To refresh the access token, issue a POST to https://webexapis.com/v1/access_token in form of a application/x-www-form-urlencoded request with the following fields in the POST body:
| Field | Value |
|---|---|
grant_type | This should be set to "refresh_token". |
client_id | Issued when creating your integration. |
client_secret | Remember this guy? You kept it safe somewhere when creating your integration. |
refresh_token | The refresh token you received from the previous step. |
curl -X POST https://webexapis.com/v1/access_token -H "Content-type: application/x-www-form-urlencoded" -d 'grant_type=refresh_token&refresh_token=ZWQzZWI0ZDEtNTcwNi00OTNkLzEtZTIz_PF84_ce861fba-6e2f-49f9-9a84-b354008fac9e&client_id=Cda095afad5c12380bb&client_secret=2af32e36cc892ef3f9ec71d849cb29eb5ab3c21'
The Webex REST API will then respond with JSON containing a new access token. Generating a new access token automatically renews the lifetime of your refresh token. Expiration times are indicated in seconds:
{
"access_token":"OGQ1MGQ2OTUtNW008fac9e",
"expires_in":1209599,
"refresh_token":"ZWQzZWI0ZDEtNTcwNi00OT49f9-9a84-b354008fac9e",
"refresh_token_expires_in":7773103,
"token_type":"Bearer",
"scope":"spark:all spark:kms"
}
Refreshing an access token before its expiration date will not cause the original access token to expire.
After the refresh token expires, using it to request a new access token from the API will result in an HTTP 400 "Invalid Request" response, such as:
{
"message": "The refresh token provided is expired, revoked, malformed, or invalid.",
"errors": [
{
"description": "The refresh token provided is expired, revoked, malformed, or invalid."
}
],
"trackingId": "API_12345678-90AB-CDEF-1234-567890ABCDEF"
}
anchorAccess Token Invalidation
anchorAn access token that's been issued to your app may be invalidated as a result of changes to a user's account. This includes, but is not limited to, the following scenarios:
- A user's account access changes as a result of updates to their email address or password.
- A user's Webex organization administrator deactivates and reactivates their account.
anchorInvoking the Webex REST API
anchorAuthenticating with another user's access token works just like your developer token; supply the token in an Authorization header like so:
GET /rooms
Authorization: Bearer THE_ACCESS_TOKEN
Accept: application/json
or in cURL it would be
curl https://webexapis.com/v1/rooms \
-H "Authorization: Bearer THE_ACCESS_TOKEN" \
-H "Accept: application/json"
The Bearer part is important as it instructs the API that this is an OAuth token instead of HTTP Basic Auth.
With the API, you can perform actions as the user such as sending a message with an interactive card to someone. To respond to events, you'll need to configure webhooks. Webhooks will let your app know when an activity has occurred so you can take action. Check out the Webhooks Guide for more information about configuring webhooks.
With cards, you can give your users even more ways to interact with your integration or service, right in the Webex clients. See the Buttons and Cards Guide for more information.