Admin - Setting Up API Client Connections

Modified on Fri, 25 Sep at 3:14 PM

Overview

Cora PPM exposes a REST API secured by an OAuth 2.0 identity server (IdentityServer). Any external tool or platform — such as n8n, Power BI, Microsoft Teams apps, or custom integrations — can connect to the Cora API to read and write project data on behalf of a specific user or a service account, provided the correct OAuth client credentials are configured in Cora by an administrator.

This article explains the two supported authentication patterns, how to configure them for common API client platforms, and what a Cora administrator needs to set up in IdentityServer for each.

Prerequisites

  • A Cora PPM site URL (e.g., https://yoursite.corasystems.com/YourInstance)

  • A Cora PPM user account with appropriate permissions, or a dedicated service account for background/automated access

  • An API client registered in Cora IdentityServer — ask your Cora administrator

  • The following details provided by your Cora administrator:

    • Client ID — identifies your integration

    • Client Secret — required for the client credentials flow (server-to-server only)

    • Scope — typically pv for Cora PPM access

Understanding the Two Authentication Patterns

Cora's IdentityServer supports two OAuth 2.0 grant types. Which one you use depends on whether a human is signing in or not.

Pattern

OAuth Grant Type

Best For

User-specific (interactive)

Implicit

Tools where a human user signs in (e.g., Power BI, Teams app, browser-based tools)

Service account (unattended)

Client Credentials

Automated workflows and polling with no user interaction (e.g., n8n automations, backend services)

Pattern 1: User-Specific Authentication (Implicit Flow)

This pattern prompts the user to sign in to Cora using their own credentials. The resulting token represents that specific user — audit trails, approvals, and record creation will be attributed to them.

How It Works

  1. Your application redirects the user (or opens a popup) to the Cora authorize endpoint:

    GET {SiteUrl}_api/identity/connect/authorize
      ?response_type=token
      &client_id={your-client-id}
      &scope=pv
      &redirect_uri={your-callback-url}
      &state={random-csrf-token}
  2. Cora's IdentityServer displays its login page. The user enters their Cora credentials.

  3. After a successful login, Cora redirects the browser to your redirect URI with the bearer token in the URL fragment (the # part of the URL):

    https://yourapp.com/auth-callback.html#access_token=eyJ...&token_type=Bearer&expires_in=3600&state=abc123
  4. Your application extracts access_token from the fragment, validates the state value (CSRF check), and stores the token.

  5. Include the token in all subsequent API requests:

    Authorization: Bearer {access_token}
  6. Tokens expire (typically after 3600 seconds / 1 hour). Your application should check the expiry and prompt the user to re-authenticate before the token expires. There are no refresh tokens in the implicit flow.

What is the Redirect URI?

The redirect URI is only relevant to the implicit flow — it has no meaning in client credentials.

When Cora's IdentityServer finishes authenticating a user, it needs to know where to send the token back to. It does this by redirecting the browser to the redirect URI you specified in the authorize request, with the token appended as a URL fragment.

Key rules for the redirect URI:

  • It must be registered in advance by a Cora administrator against your API client in IdentityServer. If the URI in your request doesn't exactly match a registered value, Cora will reject the request with a redirect_uri mismatch error. This is a security control to prevent token hijacking.

  • It must be a real page your application serves — because the browser will actually navigate to it. That page's only job is to extract the token from the URL fragment and pass it back to your main application.

  • Why the URL fragment? Browsers do not send URL fragments to the server — they only exist client-side. This means the token is never transmitted to your web server in the redirect request, reducing the risk of it being logged or intercepted server-side.

Example: an application hosted at https://yourapp.com/corateamsapp/ would register its redirect URI as:

https://yourapp.com/corateamsapp/auth-callback.html

Setting This Up in Common Tools

Power BI (custom connector): Build a custom Power BI connector with OAuth support, pointing to the Cora authorize endpoint. Register the Power BI callback URL as the redirect URI in Cora IdentityServer. Alternatively, you can use a static bearer token pasted into a Web connector's custom Authorization header — but this token will expire and need manual replacement.

Microsoft Teams Apps: Use the Teams JS SDK's microsoftTeams.authentication.authenticate() to open the Cora login in a managed popup. After the user authenticates, Cora redirects to your registered callback page, which extracts the token from the URL fragment and passes it back to the app. Store the token in localStorage for the duration of the session.

Browser-based / custom web apps: Open a popup to the Cora authorize URL. Handle the redirect in a lightweight callback page that parses the URL fragment and posts the token back to the main window via window.postMessage().

Pattern 2: Service Account Authentication (Client Credentials Flow)

This pattern is used when there is no interactive user — for example, automated workflows, scheduled jobs, or background polling. A pre-configured service account credential is used to obtain a token on behalf of the integration itself.

Important: This token represents the service account, not any specific user. Actions taken with it will appear under that service account in Cora's audit trail. Use a dedicated service account rather than a personal user account.

How It Works

  1. Your application sends a POST request directly to the Cora token endpoint — no browser, no login page:

    POST {SiteUrl}_api/identity/connect/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials
    &client_id={your-client-id}
    &client_secret={your-client-secret}
    &scope=pv
  2. Cora responds with a bearer token:

    {
      "access_token": "eyJ...",
      "token_type": "Bearer",
      "expires_in": 3600
    }
  3. Include the token in all API requests:

    Authorization: Bearer {access_token}
  4. Cache the token and refresh it before it expires (recommended: refresh ~60 seconds before expiry). Do not request a new token for every API call.

No redirect URI is involved — this is a direct server-to-server call.

Setting This Up in Common Tools

n8n: Configure an OAuth2 Credential in n8n with Grant Type = Client Credentials, Token URL = {SiteUrl}_api/identity/connect/token, Client ID, Client Secret, and Scope = pv. n8n will automatically acquire and refresh the token. Alternatively, use an HTTP Request node to POST to the token endpoint and store the result in a variable for subsequent nodes.

Power Automate / Logic Apps: Use an HTTP action to POST to the token endpoint. Parse the JSON response to extract access_token. Pass the token as an Authorization header in subsequent HTTP actions. Store credentials securely in Azure Key Vault or as Power Platform environment variables — never hardcoded.

Custom scripts / Azure Functions / backend services: Implement a token cache (in-memory or distributed). On startup and before each batch of requests, check whether the cached token is still valid and re-request when approaching expiry.

Administrator Setup: Registering an API Client in Cora IdentityServer

Before any external tool can connect, a Cora administrator must register an OAuth client in IdentityServer. The required configuration differs by flow:

Setting

Implicit Flow (Interactive)

Client Credentials (Service Account)

Client ID

Any unique identifier (e.g., powerbi-integration)

Any unique identifier (e.g., n8n-service)

Client Secret

Not used

Required — must be kept secret and stored securely

Grant Type

implicit

client_credentials

Allowed Scopes

pv

pv

Redirect URI(s)

Must exactly match the callback URL(s) the application will send

Not applicable

Associated User

N/A — token represents the signed-in user

A dedicated Cora service account

API Base URL and Key Endpoints

All Cora API calls use the following base URL pattern — note the underscore before api:

{SiteUrl}_api

For example: https://yoursite.corasystems.com/YourInstance_api

Method

Endpoint

Description

GET

/projectRegisters

List all project registers

GET

/projectRegisters/{id}

Get register schema and fields

GET

/projectRegisters/{id}/FlatRecords

Get paginated records

POST

/projects/{projectId}/projectRegister/{registerId}/records

Create a record

PUT

/projectRegisters/{registerId}/{userId}/records

Update records

GET

/projects

List projects

GET

/users

List users

GET

/identity/connect/userinfo

Get the current user's profile (name, email, ID)

Tips & Best Practices

  • Never expose client secrets in browser or frontend code. Client secrets must only be used in server-side or backend code. Use the implicit flow for user-facing tools.

  • Cache tokens. Request a new token only when the current one is near expiry — not on every API call. Repeatedly hitting the token endpoint may be rate-limited.

  • Validate the OAuth state parameter when using the implicit flow to prevent CSRF attacks.

  • Use a dedicated service account for automated integrations rather than a personal user account, so access doesn't break if an employee leaves.

  • Store secrets securely — use Azure Key Vault, environment variables, or your platform's secret management (e.g., n8n credentials vault, Power Platform environment variables). Never hardcode secrets in scripts or configuration files.

  • Handle 401 responses gracefully. A 401 Unauthorized means the token has expired. Re-authenticate rather than failing silently.

  • Refresh proactively. Refresh the token ~60 seconds before expiry rather than waiting for a 401 to avoid failed requests mid-operation.

Troubleshooting

Symptom

Likely Cause

Resolution

401 Unauthorized on all requests

Token expired or missing

Re-authenticate or refresh the token; confirm Authorization: Bearer ... header is set correctly

invalid_client error from token endpoint

Wrong Client ID or Secret

Verify credentials with your Cora administrator

invalid_scope error

Scope not permitted for this client

Ask your Cora administrator to grant the pv scope to your client

redirect_uri mismatch

Callback URL not registered in IdentityServer

Ask your Cora administrator to register your exact redirect URI against the OAuth client

OAuth popup blocked

Browser blocked the popup window

Ensure your browser allows popups from the application's origin

Token obtained but API returns 403 Forbidden

User or service account lacks permissions in Cora

Check the account's Cora role and project access with your administrator

Sign-in popup closes but nothing happens

Redirect URI page failed to communicate back to the main window

Ensure the callback page is correctly implemented and that the redirect URI exactly matches the registered value

  • Cora PPM REST API Reference

  • Managing OAuth Clients in Cora IdentityServer

  • Cora PPM Permissions and Roles

  • Setting Up the Cora Teams App

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article