Edit on GitHub

OAuth2 authentication

The App framework provides support for authenticating with remote services using OAuth2, including storage of app secrets and user tokens.

There are three operations that can be performed:

  1. Register the client ID and secret for a remote OAuth2 provider
  2. Set or update a user’s access token
  3. Get a user’s access token

The operations can be performed in two ways:

  • Using HTTP REST endpoints
  • Using a driver

OAuth2 authentication flow 

The OAuth2 authentication flow is initiated by the user invoking an App call, usually from a slash command or form. The call requires that the oauth2_app and oauth2_user context fields are expanded with expand level all.

The App returns a URL that redirects the user to the App’s /oauth2/connect endpoint, where a URL to the OAuth2 provider is returned, redirecting the user to continue the flow.

When the user has completed their authentication with the remote provider, they are redirected to the App’s /oauth2/complete endpoint to complete the flow.

graph TD A[User invokes an App call
using a slash command] --> B[Call returns URL to start
authentication flow] B -->|User clicks URL
Mattermost client opens browser| C[Mattermost redirects user to
App /oauth2/connect endpoint] C --> D[App returns redirect URL
to OAuth2 provider] D -->|User authenticates with provider| E[Provider redirects to
App /oauth2/complete endpoint] E --> F[App exchanges authentication
code for token] F --> G[App stores user's token]

Use HTTP REST endpoints 

Endpoint URL 

OAuth2 data is managed using a single HTTP REST endpoint:

<mattermost_site_url>/plugins/com.mattermost.apps/api/v1/oauth2

Replace <mattermost_site_url> with the base URL to the Mattermost server. The <mattermost_site_url> value can be obtained from a call request context.

Authorization 

An authorization token is required when invoking HTTP REST endpoints for OAuth2. The token must be set in the Authorization header as a bearer token. The bot_access_token or acting_user_access_token field of the call request context will contain the token; either token can be used.

Register a remote OAuth2 provider with HTTP REST 

Example HTTP request to register the client ID and secret for a remote OAuth2 provider:

POST /plugins/com.mattermost.apps/api/v1/oauth2/app HTTP/1.1
Authorization: Bearer xxxxxxxxxxxx
Content-Type: application/json

{
    "client_id": "xxxxxxxxxxxx",
    "client_secret": "xxxxxxxxxxxx"
}

Set or update a user access token with HTTP REST 

Example HTTP request to set a user access token:

POST /plugins/com.mattermost.apps/api/v1/oauth2/user HTTP/1.1
Authorization: Bearer xxxxxxxxxxxx
Content-Type: application/json

{
    "token": "xxxxxxxxxxxx"
}

Get a user access token with HTTP REST 

Example HTTP request to get a user access token:

GET /plugins/com.mattermost.apps/api/v1/oauth2/user HTTP/1.1
Authorization: Bearer xxxxxxxxxxxx
Accept: application/json

Example response:

{
    "token": "xxxxxxxxxxxx"
}

Use a driver 

Register a remote OAuth2 provider with a driver 

Example Golang driver code to register the OAuth2 provider client ID and client secret:

// configure is the App call invoked by the system administrator to register OAuth2 provider details.
// The call should be configured to accept two values: client_id and client_secret.
func configure(w http.ResponseWriter, req *http.Request) {
	// Decode the call request data
	creq := new(apps.CallRequest)
	err := json.NewDecoder(req.Body).Decode(creq)
	if err != nil {
		// handle the error
	}
	// Read the client_id and client_secret values from the request
	clientID, ok := creq.Values["client_id"].(string)
	if !ok {
		// handle the error
	}
	clientSecret, ok := creq.Values["client_secret"].(string)
	if !ok {
		// handle the error
	}
	// Get an instance of the API client as the acting user
	asUser := appclient.AsActingUser(creq.Context)
	// Register the OAuth2 provider's details (client ID and client secret)
	err = asUser.StoreOAuth2App(apps.OAuth2App{
		ClientID:     clientID,
		ClientSecret: clientSecret,
	})
	if err != nil {
		// handle the error
	}
	// Respond with a success message
	err = json.NewEncoder(w).Encode(
		apps.NewTextResponse("updated OAuth client credentials"),
	)
	if err != nil {
		// handle the error
	}
}

Set or update a user access token with a driver 

Example Golang driver code to set a user access token:

// oauth2Complete is the App call invoked at the end of an OAuth2 authorization flow
func oauth2Complete(w http.ResponseWriter, req *http.Request) {
	// Decode the call request data
	callRequest := new(apps.CallRequest)
	err := json.NewDecoder(req.Body).Decode(callRequest)
	if err != nil {
		// handle the error
	}
	// Read the authorization code from the call request values
	authCode, ok := callRequest.Values["code"].(string)
	if !ok {
		// handle the error
	}
	// Exchange the authorization code for a token
	token, err := oauth2Config(callRequest).Exchange(context.Background(), authCode)
	if err != nil {
		// handle the error
	}
	// Get an instance of the API client as the acting user
	client := appclient.AsActingUser(callRequest.Context)
	// Store the OAuth2 token for the acting user
	err = client.StoreOAuth2User(token)
	if err != nil {
		// handle the error
	}
	// Return a success response
	err = httputils.WriteJSON(w, apps.NewDataResponse(nil))
	if err != nil {
		// handle the error
	}
}

OAuth2 configuration 

The Golang oauth2Config function referenced in the example above is responsible for creating a oauth2.Config (godoc) struct which contains the necessary information to exchange an authorization code for a token.

Example Golang code for the oauth2Config function referencing a Google OAuth2 provider:

func oauth2Config(creq *apps.CallRequest) *oauth2.Config {
    return &oauth2.Config{
        ClientID:     creq.Context.OAuth2.ClientID,
        ClientSecret: creq.Context.OAuth2.ClientSecret,
        Endpoint:     google.Endpoint,
        RedirectURL:  creq.Context.OAuth2.CompleteURL,
        Scopes: []string{
            "https://www.googleapis.com/auth/calendar",
            "https://www.googleapis.com/auth/userinfo.profile",
            "https://www.googleapis.com/auth/userinfo.email",
        },
    }
}

Get a user access token with a driver 

Example Golang driver code to get a user access token:

func useRemoteService(w http.ResponseWriter, req *http.Request) {
	// Decode the call request data
	callRequest := new(apps.CallRequest)
	err := json.NewDecoder(req.Body).Decode(callRequest)
	if err != nil {
		// handle the error
	}
	// Get an instance of the API client as the acting user
	client := appclient.AsActingUser(callRequest.Context)
	// Get the user's token
	var userToken string
	err = client.GetOAuth2User(&userToken)
	if err != nil {
		// handle the error
	}
	// Use the token
	// ...
	// Return a success response
	err = httputils.WriteJSON(w, apps.NewDataResponse(nil))
	if err != nil {
		// handle the error
	}
}

Did you find what you were looking for?

Thank you! We appreciate your feedback.
ร—

Tell us more

Your feedback helps us improve the Mattermost developer documentation.

Have a feature request? Share it here.

Having issues? Join our Community server.