DS Server: Authorizing Angular Client Components
The DS Server Angular components implement an integrated, implicit OAuth security handling. In case, the client ID and client secret is passed as a property to the view, the component takes care of the rest. This article shows how to use the component only using an access token.

Implicit OAuth Workflow
The DS Server Angular components implement an integrated, implicit OAuth security handling. In case, the client ID and client secret is passed as a property to the view, the component takes care of the complete OAuth workflow to request a valid access token.
<tx-ds-document-editor
width="1024px"
height="1024px"
serviceURL="https://trial.dsserver.io"
oauthClientID="dsserver.u5NQQHkgjmCRAOeChUVc19zNFJ9aivKz"
oauthClientSecret="tPGgkutg8oYuSHPbfuRfE5DMf9arUCEg"
</tx-ds-document-editor>
The following diagram shows the client credentials workflow that connects the client DocumentEditor directly with DS Server by sending the client credentials to DS Server to retrieve a valid access token:
Using Access Tokens
The disadvantage of the above method is that the client credentials are exposed client-side. To avoid that, the components can be authorized directly with an access token:
<tx-ds-document-editor
width="500px"
height="500px"
serviceURL="https://trial.dsserver.io"
accessToken="Ghgf6376722GGJHFFJGHDOOIGD56657665">
</tx-ds-document-editor>
The next diagram shows the authorization with an access token that has been acquired by a server application in between:
In order to retrieve the access token from the DS Server Web API endpoints, a server-side process is required. In this case, the credentials are securely stored on the server and the client will only see the used access token.
Web API
To demonstrate this process, an ASP.NET Core web application is used to provide a Web API that requests the OAuth access tokens from DS Server in order to return a valid access token. This endpoint is then called by Angular before the view component is rendered.
The following code shows the implementation of the Web API method AccessToken:
[HttpGet]
[Route("AccessToken")]
public async System.Threading.Tasks.Task<ActionResult> AccessTokenAsync() {
// security credentials
string clientId = "";
string clientSecret = "";
string serviceUrl = "https://trial.dsserver.io";
string ClientCredentials = "client_credentials";
AccessTokenResponse token;
HttpClient m_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 = await m_client.SendAsync(tokenRequest);
// retrieve and return the token
var tokenResponseStream = await tokenResponse.Content.ReadAsStringAsync();
token = JsonConvert.DeserializeObject<AccessTokenResponse>(tokenResponseStream);
return Ok(token);
}
public string UrlEncode(Dictionary<string, string> dict) {
return string.Join("&", dict.Keys.Select(k => $"{k}={WebUtility.UrlEncode(dict[k])}"));
}
Injectable Service
In the Angular application, a service is implemented to call the Web API and to return the access token:
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class OauthService implements Resolve<any> {
public _http: HttpClient;
public _baseUrl: string;
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
this._http = http;
this._baseUrl = baseUrl;
}
resolve() {
return this._http.get<any>(this._baseUrl + 'oauth/accesstoken');
}
}
The service implements a resolve() method that is invoked when the navigation starts. The router waits for the data to be resolved before the route is finally activated. This must be defined in the imports section of the app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { DocumentEditorModule } from '@txtextcontrol/tx-ng-ds-document-editor';
import { OauthService } from './oauth.service';
@NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
pathMatch: 'full',
resolve: { token: OauthService } },
]),
DocumentEditorModule
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule { }
In the home.component.ts, the result of this attached service is passed to the property _accessToken:
import { ApplicationInitStatus, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.component.html'
})
export class HomeComponent implements OnInit {
_accessToken: string = "";
constructor(private _routes: ActivatedRoute) { }
ngOnInit(): void {
this._routes.data.subscribe((response: any) => {
this._accessToken = response.token.accessToken;
})
}
}
This _accessToken is then used directly in the home.component.html:
<tx-ds-document-editor
width="500px"
height="500px"
serviceURL="https://trial.dsserver.io"
accessToken="{{ _accessToken }}">
</tx-ds-document-editor>
Is this Safe?
The positive of the above method is that the client credentials are not exposed client-side. But the security problem is now shifted to the server as the Web API is exposed and could be accessed by other requests. In order to avoid that, the Web API should be secured. For example by using one of the following concepts:
- CORS: Enable only specific hosts.
- Security Middleware: Filter requests (used in this demo).
- Another Authorization: Use second authorization (login) for the Web API.
You can test this method by downloading the sample from our GitHub repository. Let us know, if you have any questions.
Download and Fork This Sample on GitHub
We proudly host our sample code on github.com/TextControl.
Please fork and contribute.
Requirements for this sample
- DS Server (trial)
- Visual Studio 2019
Angular
Integrate document processing, editing, sharing, collaboration, creation, electronic signatures, and PDF generation into your Angular Web applications.
Related Posts
Implementing a Security Middleware for Angular Document Editor Applications…
This article shows how to implement a security middleware for Angular Document Editor applications using ASP.NET Core. The middleware is used to validate access tokens and to protect the Document…
Impressions from Web Developer Conference WDC 2023 in Hamburg, Germany
This week we sponsored and exhibited at the Web Developer Conference in Hamburg, Germany. In this article you can see some pictures of our booth area and the conference.
Impressions from NDC London 2023
Last week, we exhibited at NDC London 2023 in the center of London city and sponsored the attendee party. In this article, you will find some impressions of our booth area and the overall conference.
See Text Control at DEVintersection Fall 2022 in Las Vegas
In December, DEVintersection is coming back to the MGM Grand in Las Vegas. We will be exhibiting at this conference to show our digital document processing technology.
Impressions from NDC Oslo 2022
Last week, we exhibited at NDC Oslo 2022 at the Oslo Spektrum in the center of the city. More than 2500 attendees met to learn from international speakers from around the world. See some…