--- title: "Part 2: Services & Dependencies" slug: "part-2-services-dependencies" updated: 2025-10-21T03:01:27Z published: 2025-10-21T03:01:27Z canonical: "docs.processmaker.com/part-2-services-dependencies" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.processmaker.com/llms.txt > Use this file to discover all available pages before exploring further. # Part 2: Services & Dependencies To achieve our application's desired functionality, we'll create two services. These services will manage the access token storage and facilitate communication with the ProcessMaker API via the SDK. Completed code: [live example](https://stackblitz.com/edit/stackblitz-starters-vuuurx) / [download example](https://github.com/ProcessMaker/angular4pm/tree/part-2) ## Step 1: Create the OAuth Client App Follow this step-by-step guide to create your OAuth application [here](/o/-LJ0aNaUl77b5HIzdH7-/s/PyTHGwZ0VereJkRNmGxE/~/changes/29/authentication/creating-a-client-application). > [!CAUTION] > You MUST create the OAuth Client Application in order to consume the ProcessMaker API. ## Step 2: Set Up ### Main TS **main.ts** ```typescript import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; platformBrowserDynamic() .bootstrapModule(AppModule) .catch((err) => console.error(err)); ``` In the above file, we are starting Angular. Note line 5: this is where we bring in our environment variables which we will use to contain all our sensitive information. > [!TIP] > The `.gitignore` file already contains the rule to exclude your actual `environment.ts` file from any commits. Just make sure to copy and rename the example file! ### The Index **index.html** ```xml ProcessMaker 4 - Angular ``` We are utilizing [getbootstrap.com](http://getbootstrap.com), as that is what the ProcessMaker form builder is built with. Our forms utilize the 12 column grid system that bootstrap is so well known for, as well as other niceties that make our lives easier. There are CDNs in the html file for fewer steps during installation, but if you prefer to have a local offline (if you are behind a corporate VPN perhaps), you can replace the CDN links. > [!WARNING] > The current version of the application uses bootstrap version 4.1.3 and jquery 3.3.1. ### AppModule Next, we'll update the `app.module.ts` file from the previous section to incorporate the Angular router. This is going to tell the application what to render when a user does an action, such as opening the form. This is the modified code. **app.module.ts** ```typescript import { NgModule } from '@angular/core'; import '@angular/compiler'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { AppComponent } from './components/app.component'; import { AppRoutingModule } from './routing/app-routing.module'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, HttpClientModule, FormsModule, ReactiveFormsModule, CommonModule, AppRoutingModule, ], providers: [], bootstrap: [AppComponent], }) export class AppModule {} ``` ### Router Create the directory `routing` inside `src/app/`, and then add the file `app-routing.module.ts`. For now, we will just make it a very simple file since it will not be used yet, at least not until we have somewhere to route TO! **app-routing.module.ts** ```typescript import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'tasks', pathMatch: 'full', runGuardsAndResolvers: 'always', }, { path: '**', redirectTo: 'tasks', runGuardsAndResolvers: 'always', }, ]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule], }) export class AppRoutingModule {} ``` Right now, you will still see the Hello John on the webpage. We need to add a few more things before we will start seeing our application come together. ### Guard The Auth Guard is akin to a security checkpoint. Before navigating to a route (think of it as a destination within your application), this checkpoint checks if the user has the necessary permissions to access that route. In more technical terms: - It's a service that implements a specific interface (CanActivate, for instance). - When a user tries to navigate to a route, the Auth Guard runs its logic. - If the logic returns true, navigation proceeds. - If it returns false, navigation is halted, often redirecting the user elsewhere. For example, if you have a route that should only be accessible to logged on users, as is our case, an Auth Guard can check if the user is logged on. If they are, they can proceed to the inbox or form. If not, they will be redirected to the log on page. Here is the code for our guard. Place it inside a new folder called `guards` and name is `auth.guard.ts`. **auth.guard.ts** ```typescript import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, } from '@angular/router'; import { AuthService } from '../services/auth.service'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate { // Injecting AuthService to check authentication status and Router to navigate constructor(private authService: AuthService, private router: Router) {} // The canActivate method is called by Angular to determine if a route can be activated canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean { // Perform additional authentication checks if needed this.authService.checkAuthStatus(); // If the user is authenticated, allow the route activation if (this.authService.authenticated) { return true; } else { // If the user is not authenticated, redirect to the login page with the return URL // and deny the route activation this.router.navigate(['login'], { queryParams: { returnUrl: state.url }, }); return false; } } } ``` ## Step 3: Services ### DB This file interfaces with local storage for basic CRUD operations like saving the access token. **db.service.ts** ```typescript import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class DbService { constructor() {} /** * Method to save a key-value pair to the local storage. * @param key - The key under which the value will be stored. * @param value - The value to be stored. */ public save(key: string, value: string): void { try { // Attempt to save the key-value pair to the local storage localStorage.setItem(key, value); } catch (error) { // Log an error message if the operation fails console.error( `Failed to save value for key "${key}" to local storage.`, error ); } } /** * Method to load a value from the local storage by its key. * @param key - The key of the value to be retrieved. * @returns The value associated with the specified key, or null if the key does not exist. */ public load(key: string): string | null { try { // Attempt to retrieve the value associated with the specified key from the local storage return localStorage.getItem(key); } catch (error) { // Log an error message if the operation fails console.error( `Failed to load value for key "${key}" from local storage.`, error ); return null; } } /** * Method to remove a key-value pair from the local storage by its key. * @param key - The key of the value to be removed. */ public remove(key: string): void { try { // Attempt to remove the key-value pair associated with the specified key from the local storage localStorage.removeItem(key); } catch (error) { // Log an error message if the operation fails console.error( `Failed to remove value for key "${key}" from local storage.`, error ); } } /** * Method to clear all key-value pairs from the local storage. */ public clear(): void { try { // Attempt to clear all key-value pairs from the local storage localStorage.clear(); } catch (error) { // Log an error message if the operation fails console.error('Failed to clear local storage.', error); } } } ``` ### Auth > [!WARNING] > This file depends on the db service, as it needs it to store the access token. There are four methods to this service: - login - This is the entry point for when the user will click on the login button. - logout - This erases the storage and the access token. - checkAuthStatus - This tells us if the user has an access token and is authenticated or not. - getAccessToken - This is the main method of the class. This is where we get our access token from ProcessMaker, and you can see we are using here the `environment.ts` variables. **auth.service.ts** ```typescript import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { DbService } from 'src/app/services/db.service'; import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root', }) export class AuthService { public authenticated: any; constructor( private http: HttpClient, private router: Router, private db: DbService ) {} // Method to check the user's authentication status checkAuthStatus() { // Retrieve the access token from local storage const token = this.db.load('access_token'); // Check if the token exists if (token) { // Optionally, you can add more logic here to validate the token, such as checking its expiration date // If the token is valid, set the authenticated status to true this.authenticated = true; } else { // If the token does not exist or is invalid, set the authenticated status to false this.authenticated = false; } } // Method to initiate the OAuth login process login() { // Define the OAuth parameters const params = [ 'response_type=code', `client_id=${environment.clientId}`, // Use environment variable 'scope=*', encodeURIComponent(`redirect_uri=${environment.redirectUri}`), // Use environment variable ]; // Redirect the user to the OAuth authorization endpoint window.location.href = environment.oauthAuthorizeUrl + '?' + params.join('&'); } // Method to log out the user logout() { // Clear authentication status and local storage this.authenticated = false; this.db.clear(); // Redirect the user to the login page this.router.navigateByUrl('login'); } // Method to get the access token using the authorization code getAccessToken(code: string) { // Define the payload for the OAuth token request const payload = new HttpParams() .append('grant_type', 'authorization_code') .append('code', code) .append('client_secret', environment.clientSecret) // Use environment variable .append('client_id', environment.clientId); // Use environment variable // Make a POST request to the OAuth token endpoint this.http .post( environment.oauthUrl, // Use environment variable payload, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, } ) .subscribe( (response) => { // Check if the access token is present in the response if ((response as any)['access_token']) { // Save the access token and mark the user as authenticated this.db.save('access_token', (response as any)['access_token']); this.authenticated = true; this.router.navigateByUrl('tasks'); } else { // If the access token is not present, mark the user as unauthenticated this.authenticated = false; this.router.navigateByUrl('login'); } }, (error) => { // Handle any errors that occur during the request console.error( 'An error occurred while fetching the access token:', error ); this.authenticated = false; this.router.navigateByUrl('login'); } ); } } ``` ## Step 4: The ProcessMaker SDK We will be utilizing the ProcessMaker SDK for Angular. ProcessMaker utilizes Swagger / OpenAPI for our documentation and API SDKs. Any of the supported SDKs are available to generate via the Artisan CLI tool. If you want to learn how to use the swagger-based SDK, you can see a video tutorial here: [Embedded content](https://www.youtube.com/embed/rR79byOjSYo?t=8) Below are the list of SDKs that can be generated via the command from within your root directory of your ProcessMaker application. ```plaintext php artisan processmaker:sdk ``` **Available SDKs** ```plaintext ada ada-server android apache2 apex asciidoc aspnetcore avro-schema bash crystal c clojure cwiki cpp-qt5-client cpp-qt5-qhttpengine-server cpp-pistache-server cpp-restbed-server cpp-restsdk cpp-tizen cpp-ue4 csharp csharp-netcore csharp-nancyfx dart dart-dio dart-dio-next dart-jaguar eiffel elixir elm erlang-client erlang-proper erlang-server fsharp-functions fsharp-giraffe-server go go-server go-gin-server graphql-schema graphql-nodejs-express-server groovy kotlin kotlin-server kotlin-spring kotlin-vertx ktorm-schema haskell-http-client haskell java jaxrs-cxf-client java-inflector java-msf4j java-pkmst java-play-framework java-undertow-server java-vertx-web jaxrs-cxf jaxrs-cxf-extended jaxrs-cxf-cdi jaxrs-jersey jaxrs-resteasy jaxrs-resteasy-eap jaxrs-spec javascript javascript-apollo javascript-flowtyped javascript-closure-angular jmeter k6 lua markdown mysql-schema nim nodejs-express-server objc ocaml openapi openapi-yaml plantuml perl php php-laravel php-lumen php-slim4 php-symfony php-mezzio-ph powershell protobuf-schema python-legacy python python-flask python-aiohttp python-blueplanet r ruby ruby-on-rails ruby-sinatra rust rust-server scalatra scala-akka scala-akka-http-server scala-finch scala-gatling scala-lagom-server scala-play-server scala-sttp scalaz spring dynamic-html html html2 swift5 typescript typescript-angular typescript-aurelia typescript-axios typescript-fetch typescript-inversify typescript-jquery typescript-nestjs typescript-node typescript-redux-query typescript-rxjs go-echo-server ``` For convenience, the application already contains the SDK files that are necessary for the applications functions in the folder `api` which resides at the root of the application, sibling to the `src` directory.