DS Server implements OAuth 2.0 as the industry standard authorization protocol. Authorization is the process by which someone is given the ability to gain access to a resource.
Security Profiles
In DS Server, you create security profiles for users or projects that can access the included services and Web APIs. The profiles contain Client ID and Client Secret pairs that provide access to these resources.
OAuth 2.0 Flows
DS Server supports two OAuth 2.0 flows: the Authorization Code Flow and the Client Credentials Flow.
Client Credentials Flow
Typically, the Client Credentials Flow is used when the client application needs to access resources on its own behalf. The client application uses its own credentials to authenticate and obtain an access token.
This workflow should not be used if the Client ID and the Client Secret are visible to the public, such as in JavaScript code. This flow implies lower security because the security pair is sent to the OAuth server for direct exchange with an access token. Therefore, in DS Server, this flow must be enabled separately for each security profile.
For machine-to-machine applications that run on your back end, the system authenticates and authorizes the application, not a user. And the credentials are not visible to the public and are stored securely on the back end.
The client credential flow is shown in the following diagram.
The credentials are sent to the authentication endpoint of DS Server using a Http Post request. After verification, the valid access token is returned. The scope additional value is mirrored, which can be used to define a specific application access scope for this request.
Here is a simple example of how to use the client credentials flow in a C# application:
private string GetAccessTokenClientCredentials() | |
{ | |
// Security credentials | |
string clientId = ""; | |
string clientSecret = ""; | |
string serviceUrl = "https://trial.dsserver.io"; | |
string clientCredentials = "client_credentials"; | |
BearerToken token; | |
HttpClient client = new HttpClient(); | |
// Generate the payload | |
var payload = new Dictionary<string, string> | |
{ | |
["grant_type"] = clientCredentials, | |
}; | |
// Token endpoint | |
string requestUri = $"{serviceUrl}/oauth/token"; | |
// Create the request message | |
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, requestUri) | |
{ | |
Content = new StringContent( | |
UrlEncode(payload), | |
Encoding.UTF8, | |
"application/x-www-form-urlencoded") | |
}; | |
// Add basic auth header containing client id and secret | |
string credentials = $"{clientId}:{clientSecret}"; | |
byte[] credentialsUtf8 = Encoding.UTF8.GetBytes(credentials); | |
string credentialsB64 = Convert.ToBase64String(credentialsUtf8); | |
tokenRequest.Headers.Authorization = | |
new AuthenticationHeaderValue("Basic", credentialsB64); | |
// Send the request | |
var tokenResponse = client.SendAsync(tokenRequest).Result; | |
// Retrieve and return the token | |
var tokenResponseStream = tokenResponse.Content.ReadAsStringAsync().Result; | |
token = JsonConvert.DeserializeObject<BearerToken>(tokenResponseStream); | |
return token.AccessToken; | |
} |
The implementation of the BearerToken class is as follows:
public sealed class BearerToken | |
{ | |
[JsonProperty(PropertyName = "access_token")] | |
public string AccessToken { get; set; } | |
[JsonProperty(PropertyName = "token_type")] | |
public string TokenType { get; set; } | |
[JsonProperty(PropertyName = "expires_in")] | |
public int ExpiresInMilliseconds { get; set; } | |
} |
Authorization Code Flow
When the client application needs to access resources on behalf of a user, the Authorization Code Flow is used. The user is prompted to log in and grant access to the client application. The authorization code is then exchanged for an access token by the client application.
The main difference is that the response is sent to a specific endpoint of the client application. This adds another layer of security because this endpoint must be registered in the DS Server security profile.
The authorization code flow is shown in the following diagram.
The client application requests a code by providing the client ID and the redirect URI endpoint. If the client ID and the registered redirect URI match, DS Server returns an authorization code to the specified endpoint. This code can be exchanged for an access code by sending it to DS Server along with the client secret. If valid, an access token is returned and can be used to access DS Server resources.
Here is a simple example of how to use the authorization code flow in a C# application. In the first step, the client ID and redirect URI are sent to the /oauth/authorize endpoint.
private async Task RequestCodeAsync() | |
{ | |
string clientId = ""; | |
string serviceUrl = "https://trial.dsserver.io"; | |
HttpClient client = new HttpClient(); | |
var queryParams = new Dictionary<string, string> | |
{ | |
["response_type"] = "code", | |
["scope"] = "signature", | |
["client_id"] = clientId, | |
["redirect_uri"] = "https://localhost:7194/Home/Token", | |
["state"] = "teststate", | |
}; | |
string requestUri = $"{serviceUrl}/oauth/authorize?{UrlEncode(queryParams)}"; | |
var codeRequest = new HttpRequestMessage(HttpMethod.Get, requestUri); | |
await client.SendAsync(codeRequest); | |
} |
The second code shows the implemented redirect Web API, which is called by DS Server by forwarding the authorization code. By sending this code along with the client secret to DS Server, it can be exchanged for an access code.
[HttpGet] | |
public string Token() | |
{ | |
string code = Request.Query["code"]; | |
// Security credentials | |
string clientId = ""; | |
string clientSecret = ""; | |
string serviceUrl = "https://trial.dsserver.io"; | |
string authorizationCode = "authorization_code"; | |
BearerToken token; | |
using (HttpClient client = new HttpClient()) | |
{ | |
// Generate the payload | |
var payload = new Dictionary<string, string> | |
{ | |
["grant_type"] = authorizationCode, | |
["code"] = code, | |
["client_id"] = clientId, | |
["client_secret"] = clientSecret, | |
["redirect_uri"] = "https://localhost:7194/Home/Token", | |
}; | |
// Token endpoint | |
string requestUri = $"{serviceUrl}/oauth/token"; | |
// Create the request message | |
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, requestUri) | |
{ | |
Content = new StringContent( | |
UrlEncode(payload), | |
Encoding.UTF8, | |
"application/x-www-form-urlencoded") | |
}; | |
// Send the request | |
var tokenResponse = client.SendAsync(tokenRequest).Result; | |
// Retrieve and return the token | |
var tokenResponseStream = tokenResponse.Content.ReadAsStringAsync().Result; | |
token = JsonConvert.DeserializeObject<BearerToken>(tokenResponseStream); | |
} | |
return token.AccessToken; | |
} |
Conclusion
DS Server implements OAuth 2.0 as the industry standard authorization protocol. The server supports two OAuth 2.0 flows: the Authorization Code Flow and the Client Credentials Flow. The Authorization Code Flow is used when the client application needs to access resources on behalf of a user. The Client Credentials Flow is used when the client application needs to access resources on its own behalf.
All client-side packages implement these flows implicitly, so you don't have to worry about authorization.