Appearance
OAuth Web Application Flow
Worked example
A minimal example of a partner app is available which can be used to walk through the flow using your own Litmus account. The source for this is also provided.
The Web Application Flow
1. Redirect the user to request authorization to access Litmus
GET https://litmus.com/oauth/authorize?
response_type=code&
client_id=XYZ&
redirect_uri=https://yourapp.com/oauth/litmus/callback&
state=xxxxxxxx& # nonce (this should be a random unguessable string)
scope=full
When logged in to Litmus, the user will be presented with your authorization request, eg
INFO
A user is only asked to authorize your application once. If you later repeat the flow (eg to get a new token after the last had expired) we skip to the next step, so later token requests should generally be invisible to your user. Because the Litmus session could end it's generally preferable to first try using a refresh token for this purpose.
2. Litmus redirects the user back to your application with a temporary code
Assuming the user authorizes your request, Litmus will send a temporary code to your redirect uri (along with relaying the state
param which you provided, which should be checked to avoid cross site request forgery):
GET https://yourapp.com/oauth/litmus/callback?code=ABCD...&state=xxxxxxxx
If the user does not approve the request you'll instead receive an error:
GET https://yourapp.com/oauth/litmus/callback?error=access_denied
Because the request is made from the context of the end user's browser, their existing session with your web application should be used to tie this request back to them.
3. Exchange the code for an access token
Your application server should POST using its client_secret
and the code
to obtain a token:
POST https://litmus.com/oauth/token
JSON POST body parameters:
Field | Description |
---|---|
client_id | REQUIRED The client ID you received from Litmus |
client_secret | REQUIRED The client secret you received from Litmus |
code | REQUIRED The code you received in the previous step |
redirect_uri | This must match redirect_uri provided in step 1, it should be omitted if this was not provided there |
grant_type | REQUIRED This must be authorization_code |
JSON response body
json
{
"access_token": "XYZ",
"expires_in": 7200, // The remaining lifetime of the token in seconds
"token_type": "Bearer" // The token type, currently always Bearer
// More fields may be provided
}
Like your client_secret
the token should be stored securely.
4. Call Litmus API methods passing the token
Make authenticated calls to our APIs from your application server using the HTTP Authorization
header:
sh
$ curl -X "POST" "https://instant-api.litmus.com/v1/emails"\
-H "Content-Type: application/json"\
-H "Authorization: Bearer a66841f0a212c0afb6344c6377df4dde0389922511540d9e3c1d11e2ab811a2e"\
-d "{\"plain_text\":\"Hello World\"}" -v
> POST /v1/emails HTTP/1.1
> Host: instant-api.litmus.com
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Type: application/json
> Authorization: Bearer a66841f0a212c0afb6344c6377df4dde0389922511540d9e3c1d11e2ab811a2e
> Content-Length: 28
>
< HTTP/1.1 200 OK
< Server: nginx
< Date: Tue, 21 Jun 2016 20:10:06 GMT
< Content-Type: application/json;charset=utf-8
< Content-Length: 58
< Connection: keep-alive
< Strict-Transport-Security: max-age=3600; includeSubdomains; preload
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
<
{
"email_guid": "113bdfdf-6d54-4cbe-8d38-dd66157e1751"
}
Scopes
Currently only one scope, full
("Use all Litmus features on your behalf") is currently provided (this is also the default when none is specified).
Token expiration and refresh
Token expiry should be anticipated (the default token time-to-live is 2hrs, but this may change).
Refresh tokens are supported and are the recommended approach to obtaining a new bearer token. Restarting the flow above will also issue a fresh token where the current litmus user has authorized your application already.
Token revocation
Token revocation should also be anticipated and handled gracefully by restarting the flow.
Request user identity data
GET
https://api.litmus.com/v2/users/current
Retrieve the name and unique identifier of the Litmus user associated with the current authorization credentials.
Examples
sh
curl -X "GET" "https://api.litmus.com/v2/users/current"\
-H "Authorization: Bearer $TOKEN"
Result Format
200 OK
json
{
"user": {
"id": 123456,
"full_name": "John Doe",
"first_name": "John",
"last_name": "Doe"
}
}
List a user's default email clients
GET
https://api.litmus.com/v2/user_settings/clients
Obtain a list of a user's default clients configured via https://litmus.com/settings/clients.
If a user has never configured default clients, this defaults to a set of popular clients.
Examples
sh
curl -X "GET" "https://api.litmus.com/v2/user_settings/clients"\
-H "Authorization: Bearer $TOKEN"
Result Format
200 OK
json
{
"clients": [
{"code":"APPMAIL5"},
{"code":"APPMAIL6"}
]
}
Request a user-specific client configuration URL
GET
https://api.litmus.com/v2/user_settings/clients/configuration_url
This is useful when you wish to link out to Litmus to allow your users to alter their default Litmus testing client set (which can be retrieved with the /v2/user_settings/clients endpoint above).
If you simply link https://litmus.com/settings/clients the user associated with the OAuth token may not match the user for the current Litmus session (as they may have switched subaccounts at some point, or they may have logged in with an entirely different account).
This endpoint allows you to retrieve a client settings URL which when followed will ensure the user is prompted to switch to a Litmus account that matches the OAuth token used to make the API request.
Generated URL Lifetime
Each generated URL has a valid lifetime of at least 1 day. It can be used multiple times before expiry.
Examples
sh
curl -X "GET" "https://api.litmus.com/v2/user_settings/clients/configuration_url"\
-H "Authorization: Bearer $TOKEN"
Result Format
200 OK
json
{
"configuration_url": "https://litmus.com/ensured_user/eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00iLCJhbGdvIjoiUlNBLU9BRVAifQ.dgGgBTD-ZgcMFZ2Fg_ywYOiWDUe6wZU7WJdUzkVSJ29K3nYj13NdrSQAOC67op8HZkACMWTTsx_K5iwDgkINRlnmatzb2q7_OKc6OHiFMVoTudSLxzLUdu-RKkkjdEKr54F03xju6jiewWPVBmX2Cf1bNSIE9VHgaKI5nZay6xHmO2Fe-sDzNvZqfF9Yp4vQEj6AtD0DlLTW4pNGUb7f2JgX3cJzchbb6d5TSzgtiCgO6c76tdzd5BMm6h2RdncfAsztGf4xJoAdaYsMF_Z_ruMijiEHOXIdYydxwKyewvE6VNRD3REXgk1ADOCX0nqHGyxjgu8s7UbBLtHK-Vg9Pw.zXJ6JAni_sovilZp.x07WQ2K-6GvSMITa7H-j5Wsc9M2fiH1FhOhZhP7jWeAcII_EWtpQy6p37_6o55kwrDHtBvo5qVL69zdLEDwHw0ckujOPZK2PFFD0kmRlt_nni-_XxtVuVbEhipqcuAGC9PPmMlsh7u2KEET9tXdx3ozKo9-pAh233P73iB-aBxWUupfqVvSoeh9E08jZ2QPp0rXx8pOwKiV6pbhK9CRAjOn6HHyYEGPoFesnMECRbUvrkgoPly17QuxjxO50cFx3VX3wFcw7BNt-LZEQUsIbzqhnQlK9b00QeVoyJn1EvLQLFdM6N2aflZ2vFHDIGiDRUWBvvA98xR4nXmzOCNXZTehGKT_v9VT0nCOw3NQRfxFleoGG0Y_wZ5r_tD5YSsux1X6-vchuQxo7l7I3cLV5NTnW63twDpfHXj9ce25bOc2QjoZ7a6ulwxMwzVA7McsVLcVOis6Ut79ST-RbAUfoNuI6717MYchqduI2_hcruQDxLP53tgyyUd_LAUT8nHWGeo7CA4JT57TazIb6hXII0P7veQbfqyq1-JWI-_DfJYyJunHB2NPJSO3mP3Ny68jDkcikwQmT-r2NqD4hZ7QnAUZKAJ8td1oDETrdU-BZBw.DfIvjD1NLlADracTQMXi-A"
}