API Security – General
SoNET uses OAuth 2.0 to secure its API. It supports all OAuth grants:
- Authorization Code Grant
- Implicit Grant
- Resource Owner Password Credentials Grant
- Client Credentials Grant
To start making API calls, you need to:
1. Register first
2. Add New Client App in the client area with proper callback URL.
3. Use your assigned Client App ID and when needed - Client App Secret with any of the grants above to generate access token
4. Send that access token with each request to ensure authorization
Each access token is generated for a certain requested scope. Some scopes are special:
-
Api.Access
Gives access to non-Site specific APIs
-
Site.Name:{Name of the Site}
Gives access to Site specific APIs
There are 3 relevant endpoints to call depending on OAuth grant:
-
Authorization Endpoint
URL where a Client redirects the User to make authorization request.
https://www.LPK7.com/mvc/oauth/user
-
Token Endpoint
URL from which a Client can request access token
https://www.LPK7.com/mvc/oauth/token
-
Token Enpoint for an Api.Access scope and Implicit Grant
URL from which a Client can request access token for Api.Access scope using Implicit Grant (good for limited trust Clients running in the browser)
https://www.LPK7.com/mvc/oauth
Important: All access tokens are short lived (valid for only a couple of minutes).
Sample: Implicit Grant – Calling non-Site specific API
This sample demonstrates how to obtain an access token using Implicit Grant and call non-Site specific API: api/TemplateObjects/GetAllTemplates
HTML<form action="/s/ImplicitGrant_General" method="post"> <input type="button" id="btnGo" name="go" value="Get Templates"> </form> <ul id="results" style="display: none"> <table id="templates"> </table> </ul>JavaScript
$(document).ready(function () { $('#btnGo').click(getAccessToken); //After SoNET calls us back – we extract access token and use it to call API var hashIndex = document.location.href.indexOf('#'); if (hashIndex > 0) { var fragment = document.location.href.substring(hashIndex + 1); var accessToken = null; var keyValuePairs = fragment.split('&'); for (var i = 0; i < keyValuePairs.length; i++) { var keyValue = keyValuePairs[i].split('='); var key = decodeURIComponent(keyValue[0]); if (key == 'access_token') { var value = keyValue[1]; accessToken = decodeURIComponent(value); break; } } if (accessToken) { $.support.cors = true; $.ajax({ type: 'GET', url: 'https://www.LPK7.com/api/TemplateObjects/GetAllTemplates', //API to call dataType: 'json', contentType: 'application/json; charset=utf-8', headers: { 'Authorization': 'Bearer ' + accessToken }, //Pass Access Token with request success: function (data) { //Bind to some sample controls for demonstration $('#results').show(); $.each(data, function (i, template) { $('#templates').append($('<tr>').append($('<td>').text('Name')).append($('<td>').text(template.Name))); }); }, error: function (error) { alert(error.statusText); } }); } } }); function getAccessToken(evt) { var url = 'https://www.LPK7.com/mvc/oauth'; //Token Endpoint for Api.Access scope url = url + '?client_id=2551ef4d-5ef8-4bf2-ade9-79dea8488f51'; //Your Client App ID url = url + '&scope=Api.Access'; //Required scope to access non-Site specific API url = url + '&redirect_uri=' + encodeURIComponent('http://mobile.client.com/s/implicitgrant_general'); //Callback URL – same page url = url + '&response_type=token'; //Implicit Grant document.location = url; }
Sample: Implicit Grant – Calling Site Specific API
This sample demonstrates how to obtain an access token using Implicit Grant and call Site specific API: odata/Sites(‘SiteName’)
HTML<form action="/s/implicitgrant" method="post"> <input type="button" id="btnGo" name="go" value="Get Site Info"> </form> <ul id="results" style="padding: 1em 0; display: none"> <li> Site Name: <span id="txtSiteName"/> </li> <li> Short Info: <div id="txtShortInfo"/> </li> </ul>JavaScript
$(document).ready(function () { $('#btnGo').click(getAccessToken); //After User approves and SoNET calls us back – we extract access token and use it to call API var hashIndex = document.location.href.indexOf('#'); if (hashIndex > 0) { var fragment = document.location.href.substring(hashIndex + 1); var accessToken = null; var keyValuePairs = fragment.split('&'); for (var i = 0; i < keyValuePairs.length; i++) { var keyValue = keyValuePairs[i].split('='); var key = decodeURIComponent(keyValue[0]); if (key == 'access_token') { var value = keyValue[1]; accessToken = decodeURIComponent(value); break; } } if (accessToken) { $.support.cors = true; $.ajax({ type: 'GET', url: "https://www.LPK7.com/odata/Sites('SampleSite')", //API to call dataType: 'json', contentType: 'application/json; charset=utf-8', headers: { 'Authorization': 'Bearer ' + accessToken }, //Pass Access Token with request success: function (data) { //Bind to some sample controls for demonstration $('#results').show(); $('#txtSiteName').text(data.SiteName); $('#txtShortInfo').html(data.HeaderShortInfo); }, error: function (error) { alert(error.statusText); } }); } } }); function getAccessToken(evt) { var url = 'https://www.LPK7.com/mvc/oauth/user'; //Authorization Endpoint url = url + '?client_id=2551ef4d-5ef8-4bf2-ade9-79dea8488f51'; //Your Client App ID url = url + '&scope=Api.Access SiteName:SampleSite'; //Api.Access and Site.Name:{SiteName} scopes url = url + '&redirect_uri=' + encodeURIComponent('http://mobile.client.com/s/implicitgrant'); //Callback URL-same page url = url + '&response_type=token'; //Implicit Grant document.location = url; }
Sample: Using Various OAuth Grants from .NET
This sample demonstrates how to obtain an access token using Client Credentials Grant, Resource Owner Password Credentials Grant and Authorization Grant with DotNetOpenAuth library and call Site specific API: odata/Sites(‘SiteName’)
C#public class SController : Controller { private static readonly string clientID = "{Your Client App ID here}" private static readonly string clientSecret = "{Your Client App secret here}" private static readonly string TOKEN_ENDPOINT = "https://www.LPK7.com/mvc/oauth/token"; private static readonly string AUTHZ_ENDPOINT = "https://www.LPK7.com/mvc/oauth/user"; private AuthorizationServerDescription _authorizationServer; public AuthorizationServerDescription AuthorizationServer { get { if (_authorizationServer == null) { _authorizationServer = new AuthorizationServerDescription() { TokenEndpoint = new Uri(TOKEN_ENDPOINT), AuthorizationEndpoint = new Uri(AUTHZ_ENDPOINT) }; } return _authorizationServer; } } private WebServerClient _webServerClient; public WebServerClient WebServerClient { get { if (_webServerClient == null) _webServerClient = new WebServerClient(AuthorizationServer, clientID, clientSecret); return _webServerClient; } string siteName = "SampleSite"; /* Client Credentials Grant */ public ActionResult ClientCredentials() { var authorization = WebServerClient.GetClientAccessToken(new[] { "Api.Access" }); if (authorization == null) return new EmptyResult(); string accessToken = authorization.AccessToken; Site site = getSite(accessToken, siteName); if (site == null) return new EmptyResult(); return View(site); } /* Resource Owner Password Credentials Grant */ public ActionResult ResourceOwnerPassword() { var authorization = WebServerClient.ExchangeUserCredentialForToken( "Admin", "test123", new[] { "SiteName:" + siteName, "Api.Access" }); if (authorization == null) return new EmptyResult(); string accessToken = authorization.AccessToken; Site site = getSite(accessToken, siteName); return View(site); } /* Authorization Code Grant */ public ActionResult UserAuthorization() { WebServerClient.RequestUserAuthorization( new[] { "SiteName:" + siteName, "Api.Access" }, new Uri(Url.Action("Callback", "S", null, Request.Url.Scheme))); return View(); } public ActionResult Callback() { //exchange authorization code for access token var authorization = WebServerClient.ProcessUserAuthorization(); if (authorization == null) return View(); if (authorization.RefreshToken != null && authorization.AccessTokenExpirationUtc.HasValue) WebServerClient.RefreshAuthorization(authorization, TimeSpan.FromSeconds(30)); //You could store refresh token or better yet entire IAuthorizationState to do not ask User again string accessToken = authorization.AccessToken; Site site = getSite(accessToken, siteName); return View(site); } private Site getSite(string accessToken, string siteName) { if (string.IsNullOrWhiteSpace(accessToken)) throw new ArgumentNullException("accessToken"); using (var httpClient = new SoNETHttpClient(accessToken)) { //with access token present - make Web Api call to get Site object string url = string.Format("https://www.LPK7.com/odata/Sites('{1}')", siteName); var apiResponse = httpClient.GetAsync(url).Result; if (!apiResponse.IsSuccessStatusCode) return null; string result = apiResponse.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject<Site>(result); } } };