Authentication
Components that require authentication from the user must implement an authentication module for the service/module they belong to. The authentication module must be named auth.js
and must be stored under either the service or module directory (i.e. [vendor]/[service]/auth.js
or [vendor/[service]/[module]/auth.js
. Appmixer currently supports three types of authentication mechanisms that are common for today's APIs: API key, OAuth 1 and OAuth 2.
Appmixer provides an easy way to configure authentication modules. Most of the time, it's just about configuring a 3rd party service provider URLs for authentication, requesting access tokens and token validation.
Authentication Module Structure
Each authentication module is a NodeJS module that returns an object with type
and definition
properties. type
can be either apiKey
, oauth
(for OAuth 1) and oauth2
(for OAuth 2). definition
is either an object or a function (useful in cases where there's a code that you need to run dynamically).
type
The type of the authentication mechanism. Any of apiKey
, oauth
and oauth2
.
definition
The definition of the authentication mechanism specific to the API service provider. An object or a function. This differs significantly between authentication mechanisms.
If the definition property is specified as a function, it that case it has one argument context. It is an object that contains either consumerKey, consumerSecret (OAuth 1) or clientId, clientSecret (OAuth 2) and it always contains callbackUrl property. This will be shown later in the examples.
Authentication mechanisms
As it was mentioned in the beginning, Appmixer authentication supports three mechanisms: API Key, OAuth 1 and OAuth 2. Each of them has a different definition.
function, object or a URL string
In the following examples we will show how a particular property of the definition object can be specified as a function, object or string. Let's demonstrate that on a requestProfileInfo property, that one is common for all authentication mechanisms.
API key
This is the most basic type of third party authentication, since you only need to provide a sort of ID and a key provided by the app in concern. In order to use this mechanism, type
property must be set to apiKey
. Here is an example from Freshdesk components:
Now we explain the fields inside the definition object:
auth (object)
This is basically the definition for the form that will be displayed to the user to collect the data required by the third party application. Freshdesk requires the domain name and the API key in order to authenticate Appmixer. So we define two fields representing those items and we define the label and tooltip that will appear in the form for each field. In this case, the auth definition will make Appmixer to render a form like this:
The values introduced by the user will be exposed in the context
object with the same keys as in the auth object. In this case we will be able to access the values as context.domain
and context.apiKey
.
requestProfileInfo (function, object or string) (optional)
While this field is optional, is recommended for a better UX. This field can be a function which returns a promise, object or a string. It is about calling an endpoint from the third party app which returns the current user info. This will be used to display a name for this account in Appmixer.
accountNameFromProfileInfo (function or string)
This field is the path in the object returned by requestProfileInfo
that points to the value that will be used as account name. Following the example, the object returned by requestProfileInfo
would have an structure like this:
We want to use the email to identify the Freshdesk accounts in Apmmixer, so we set accountNameFromProfileInfo
as contact.email
.
If requestProfileInfo
is not defined, the auth
object will be used instead. The account name will be the resolved value for the property specified by accountNameFromProfileInfo
.
validate (function, object or string)
Similar to requestProfileInfo
. This is used to validate if the authentication data entered by the user is correct. For this purpose you can call any endpoint that requires authentication, you can even use the same endpoint as requestProfileInfo
. If the data is correct, this function should resolve to any non-false value. Otherwise throw an error or resolve to false
. You can define validate
as an object. In that case, that object has the same structure as object passed into request library. In that case it will look like this:
OAuth 1
In order to use this mechanism, type
property must be set to oauth
. Here is an example from Trello components:
Note that in this case the definition is a function instead of an object, but it still returns an object with the items needed for OAuth 1 authentication, similar to API key authentication. Now we explain the fields from definition object:
accountNameFromProfileInfo (function or string)
Works exactly the same way as described on API Key section.
requestRequestToken (function, object or string)
This must be a function (or an object, or just a string URL as explained here) that returns a promise which must resolve to an object containing requestToken
and requestTokenSecret
the same way that is showed on the example. Those are needed to get the access token and become exposed by the context - context.requestToken
and context.requestTokenSecret
.
requestAccessToken (function, object or string)
This must be a function (or an object, or just a string URL as explained here) that returns a promise which must resolve to an object containing accessToken
and accessTokenSecret
the same way that is showed on the example. Usually you will be using the requestToken
and requestTokenSecret
inside this function as they are required by the OAuth 1 flow in this step. Similarly to requestRequestToken
function, accessToken
and accessTokenSecret
will become exposed by the context - context.accessToken
and context.accessTokenSecret
.
authUrl (function, object or string)
Function, object or a string URL returning auth URL. Appmixer will then use this URL to redirect the user to proper login page. The requestToken
is available in the context. The example shows the authUrl declaration using the token provided by the context.
requestProfileInfo (function, object or string) (optional)
Works exactly the same way as described in the API Key section.
validateAccessToken (function, object or string)
This property serves the same purpose as validate property in the API Key mechanism. This is used by Appmixer to test if the access token is valid and accepted by the third party app. You have access to context.accessToken
and context.accessTokenSecret
to make authenticated requests. If the token is valid, this function should resolve to any non-false value. Otherwise throw an error or resolve to false
.
OAuth 2
The latest OAuth protocol and industry-standard, OAuth 2.0 improved many things from the first version in terms on usability and implementation, while maintaining a high degree of security. It is easier to implement in Appmixer as well. In order to use this mechanism, type
property must be set to oauth2
. Here is an example from Asana auth.js:
Notice that there is no requestRequestToken
method in OAuth 2, but we there is the requestAccessToken
used to get the token and refreshAccessToken
method, which is used by Appmixer to refresh the access tokens. Now we explain the definition object properties:
accountNameFromProfileInfo (function or string)
Works exactly the same way as described in the API Key section.
authUrl (function, object or string)
Similar to OAuth 1, we should provide the authentication url for the third party app. However, due to the different authentication flows supported by OAuth 2, the way this is defined may vary according to the third party implementation. If the OAuth 2 implementation is standard, you can define the authUrl with just a string like:
Standard means, there is a response_type
parameter set to code
, then there is the client_id
, redirect_uri
, state
and scope
parameter. If the OAuth 2 implementation requires any other parameters (or the standard ones use different names), then you have to define this property as a function and provide all the additional parameters. The same logic applies to the following property requestAccessToken
.
requestAccessToken (function, object or string)
This function should return a promise with an object which contains accessToken
, refreshToken
(optional, some OAuth 2 implementations do not have refresh tokens) and accessTokenExpDate
or expires_in
(also options if the implementation does not have tokens that expire). Inside this function we call the endpoint which handles out the access tokens for the application. Inside this function you have access to context properties you need: clientId
, clientSecret
, callbackUrl
and authorizationCode
.
requestProfileInfo (function, object or string) (optional)
Works exactly the same way as described in the API Key section.
refreshAccessToken (function, object or string)
Part of the OAuth 2 specification is the ability to refresh short lived tokens via a refresh token that is issued along with the access token. This function should call the refresh token endpoint on the third party app and resolve to an object with accessToken
and accessTokenExpDate
properties, as shown in the example. You have access to context properties clientId
, clientSecret
, callbackUrl
and refreshToken
.
validateAccessToken (function, object or string)
Has the exact same purpose as the same method int the OAuth 1.
There are more ways the OAuth 2 can be implemented. It always depends on the third party server and its OAuth 2 implementation.
This is an example of Dropbox auth.js module:
It can be that simple, if the third party API implements OAuth 2 according to standards. And in this Dropbox case, their OAuth 2 implementation does not contain refresh tokens.
Sometimes the OAuth 2 needs a scope or a different scope delimiter. Here is a full example of Microsoft authentication module with such features:
scope
String or an array of strings.
scopeDelimiter
String. The default one is ,
and you can change it to ' '
for example.
Setting OAuth 1,2 secrets
The OAuth applications need some secrets: consumerKey, consumerSecret (OAuth 1), or clientId, clientSecret (OAuth 2).
You can use the Backoffice to do that. This is the preferable way.
Another way is the credentials.json file which has to be located where your auth.js file is.
Then when you pack and publish your component archive, Appmixer will read the file and store the values into Mongo DB. Later it will use them to create the context object for your auth.js module.
Last updated