Authentication¶
akoyaGO uses standard Microsoft Entra ID OAuth 2.0 for all API access. There is no akoyaGO-specific authentication layer — if you've authenticated against Dataverse before, you already know the pattern.
This page covers what's specific to akoyaGO: requesting credentials, the security role your application user needs, and the environment setup. For the flows themselves, follow the Microsoft Learn links inline.
Before you register anything
Contact your foundation's akoyaGO administrator or open a ticket with GOsupport to confirm which environment you'll be connecting to and what credentials the foundation wants to issue. Partners typically receive a tenant ID, a client ID, and either a client secret or a certificate.
Supported authentication flows¶
| Flow | When to use |
|---|---|
| Client credentials (service-to-service) | Headless integrations, ETL, audience and AP / ERP sync. The default choice for integration partners. |
| Authorization Code with PKCE | Partner-hosted apps that act on behalf of an end user. |
| Interactive | Local development, admin tools (XrmToolBox, etc.). |
See also on Microsoft Learn:
Registering an application¶
Follow Microsoft's standard procedure for registering an Entra ID application and creating either a client secret or a certificate:
- Walkthrough: Register an app with Microsoft Entra ID — Microsoft Learn
akoyaGO-specific notes:
- Redirect URIs are only needed for user-delegated flows (Authorization Code). Client-credentials apps don't use them.
- API permissions — grant Dynamics CRM
user_impersonation(application permission for client-credentials; delegated for auth-code). - Single-tenant vs multi-tenant — akoyaGO environments live in the foundation's own tenant. Partners building for a single foundation register a single-tenant app in that tenant. Partners building a product that spans multiple foundations register a multi-tenant app and obtain admin consent per foundation.
Security roles for the application user¶
Once the app is registered, the foundation admin creates an application user in the Dataverse environment and assigns it a security role. The akoyaGO managed solution ships several custom roles; integration partners typically start from one of these:
| Role (in the akoyaGO solution) | Scope | Best for |
|---|---|---|
| akoyaGO Business Central Integration User Role | Read + Write (Update) + Append + AppendTo across the full documented akoyaGO entity model (akoya_donor, akoya_fund, akoya_gift, akoya_giftpayment, akoya_request, akoya_requestpayment, akoya_accountingsettings, akoya_account, plus account, contact, and supporting tables like akoya_function, akoya_department, akoya_FundGroup, akoya_FundStatementFormat). Create privileges are limited to akoya_account, akoya_AccountSubcategory, akoya_FundStatementFormat, and akoya_GOverify. |
The default starting point for most integration partners — AP / ERP sync, payment-status reconciliation, and any flow that updates existing records (payment status, clear dates, GL coding) without creating new gifts, donors, or requests. |
| Custom partner role | Whatever the partner specifically needs. Usually a clone of the BC Integration role with extra Create privileges added, or a stripped-down read-only variant. | Any partner whose needs differ from above — a read-only audience / email-marketing sync (only Read on contact and akoya_donor), or an integration that needs to create new gifts, donors, or requests. |
Don't assign broad built-in roles
Avoid System Administrator and System Customizer for application users — both grant solution-management privileges integration users should never have. Always start from one of the akoyaGO custom roles or a derived custom role in the same environment.
Read-only sync partners
The BC Integration role is more access than a read-only sync needs. Ask the foundation admin to create a least-privilege custom role granting only prvReadakoya_* and prvReadContact on the entities the integration touches. Don't reuse the stock Dataverse "Read Only User" role — it doesn't grant read on akoya_* tables.
For the exact privilege names per entity (prvReadakoya_donor, prvCreateakoya_gift, etc.), see the Privileges section on each entity reference page.
Acquiring a token (client-credentials flow)¶
The minimum working token request:
POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id={client-id}
&client_secret={client-secret}
&scope=https://{org}.crm.dynamics.com/.default
Response body:
import msal
app = msal.ConfidentialClientApplication(
client_id="{client-id}",
authority="https://login.microsoftonline.com/{tenant-id}",
client_credential="{client-secret}",
)
token = app.acquire_token_for_client(
scopes=["https://{org}.crm.dynamics.com/.default"]
)
access_token = token["access_token"]
var app = ConfidentialClientApplicationBuilder
.Create("{client-id}")
.WithClientSecret("{client-secret}")
.WithAuthority("https://login.microsoftonline.com/{tenant-id}")
.Build();
var result = await app.AcquireTokenForClient(
new[] { "https://{org}.crm.dynamics.com/.default" }
).ExecuteAsync();
var accessToken = result.AccessToken;
Or use ServiceClient on .NET
Microsoft.PowerPlatform.Dataverse.Client.ServiceClient wraps token acquisition, refresh, and retry internally — pass a connection string and you don't manage tokens at all:
Access tokens are valid for 1 hour. Low-volume integrations can acquire a fresh token per run; high-volume clients should cache and refresh. MSAL and ServiceClient both cache automatically.
See also on Microsoft Learn:
What's next¶
- Dataverse quickstart & FAQ — make your first API call.