Authentication and authorization in SalesKing is done using the OAuth 2.0 protocol. OAuth supports different flows depending on the type of client application(website, desktop, mobile app). As a starting point we support the Server-side flow(authorisation code flow), meaning you are using a website and a server-side client(ruby,php, ..) to talk to SalesKing.
User Login
Access to SalesKing is always in a company-scope, identified by the current subdomain. A user working in multiple companies must allow an app for each account.
A login involves three steps:
- User authentication: The user MUST login to SalesKing before he can authorize any app, so we know it's really him.
- App authorization: Apps SHOULD define permissions(in scope - param) as capabilities users provide to an app. No Scope == All Permissions
- App authentication: An app MUST identify itself with their credentials(app id+secret), ensuring the user is giving their information to your app and not someone else.
Upon completion, your app is issued an user access token that enables you to access the user's information(within a company) and take actions on their behalf.
Authorisation & Permissions
Your app SHOULD define only needed permissions using the scope-parameter in authorization requests. Permissions are space delimited, each consisting of a context-name, optionally followed by(colon) a csv list of permission names. Permissions to view companies/current and users/current are always added. Also read Permissions in detail.
If you choose to add all permissions which the allowing user has, skip the scope param:
No Scope == All Permissions of the current user.
For testing and internal apps this might be ok, BUT if somebody gets hold of the access he can do BAD THINGS!!
scope=api/contacts api/invoices:create,read,update,delete api/contacts = All permissions CRUD api/invoices:read = Only read for invoices
All available permissions can be found at /api/auth_permissions, and can also be filtered: /api/auth_permissions?q=api
Server-side Flow
User authentication and app authorization are handled within our oAuth Dialog, shown on authorization requests(GET /oauth/authorize). To see this dialog the user has to login, proving its really him. The app, identified by its client_id( gen. on app creation), is authorized by the user with the given permissions(scope-param). On approval the users browser is redirected back to the given redirect-url(redirect_uri param). The redirect_uri must be within the same domain as the Site URL you specified when creating the app.
1. GET the oAuth dialog:
https://SUBDOMAIN.salesking.eu/oauth/authorize?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=api/contacts:read
and after login, a user sees something like this:
If the user clicks the "Don't Allow"-Link he gets redirected to your app's redirect_uri with the error parameter:
http://YOUR_URL?error=user_denied
2. Redirected back to your App
If the user allows your app, his browser is redirected (302) to the URL in redirect_uri with an authorization code:
http://YOUR_URL?code=SOME_LENGTHY_CODE
3. Get Access Token
The last step: app authentication, can only be done using this code. To gain permanent access your app is issued an access token which is required for all API calls.
Our token endpoint expects the following params:
https://SUB.salesking.eu/oauth/token?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
If your app is successfully authenticated, the access token, it's expiry time in seconds and the a state parameter(if used) are returned in a JSON object. You can also request an offline token, which does not expire, by adding "offline_access" to the scope param. Please be careful with such as it is a security risk.
{ "access_token":"fc4f10073d31c6cba68922f0356c6b8e", "state":"Random string you should add when requesting oAuth dialog. Security-check if its still the same.", "expires_in":3599 }
Once the token expires(default: 1 h), you will need to re-run the steps above to generate a new code and access_token. The oAuth dialog is NOT shown again if the user has already authorized your app.
4. Use Access Token
The access token is used in every request, and can be passed as an url parameter or inside the request header:
# as url param my.salesking.eu/api/contacts?access_token=THE_ACCESS_TOKEN<br>#as auth header Authorization: Bearer THE_ACCESS_TOKEN<br>
Implicit Grant (js-apps)
Javascript client apps, running in a browser, are not able to keep an app-secret in a save place. They should therefore use the Implizit Grant, which directly returns the access token. The redirect_uri must be within the same domain as the Site URL you specified when creating the app!
1. GET the oAuth dialog:
Set params[response_type]=token activates and returns the token in the callback uri.
https://SUBDOMAIN.salesking.eu/oauth/authorize?client_id=YOUR_APP_ID&response_type=token&redirect_uri=https://YourApp.com/activate_callback&scope=api/contacts:read
Your app will receive the token as url param: https://YourApp.com/activate_callback?access_token...
Browser JS apps cannot run within a SalesKing canvas page. Such apps receive encrypted params, which need the client secret to decrypt them.
Errors
If app authentication fails, an HTTP 400 is issued and an array of errors is returned as JSON:
[ {"error":"invalid_client", "error_description": "App for token could not be found" }, {"error":"invalid_client", "error_description":"Client id or secret invalid"}, {"error": "invalid_grant", "error_description":"Invalid code, only use it once."}, {"error": "invalid_grant" , "error_description": "redirect_uri is not included in app url"}, {"error": "invalid_grant" , "error_description":"The given state does not match the state when the token was requested"} ]
Example
A minimalistic PHP example to demonstrate the server-side flow: