@primno/dataverse-auth
Version:
Authenticate to Dataverse and Dynamics 365 with a connection string or OAuth 2.0. Provides a token persistence cache.
283 lines (224 loc) • 9.36 kB
Markdown
[](https://www.npmjs.com/package/@primno/dataverse-auth)
[](https://github.com/primno/dataverse/blob/main/LICENSE)


`@primno/dataverse-auth` is a library for Node.JS to authenticate to Dataverse / Dynamics 365.
`@primno/dataverse-auth` provides:
- [Authentication](
- Connection string.
- OAuth2 flow:
- Device code flow.
- Client credentials flow.
- Username/password flow.
- [Persistent token cache](
- [Authority discovery](
Works with [`@primno/dataverse-client`](https://www.npmjs.com/package/@primno/dataverse-client) to make requests to Dataverse / Dynamics 365 CE, but can be used as a **standalone library**.
> This package is part of the [Primno](https://primno.io) framework.
`@primno/dataverse-auth` works with Dataverse / Dynamics 365.
Dynamics 365 CE (on-premises) is supported since version 9.0 with CBA/IFD deployment (ADFS 2019+ with OAuth enabled in deployment settings).
> **Tip** If you are using Dynamics 365 App for Outlook on your on-premises environment, the prerequisite are met.
## Quick start
### Installation
```bash
npm install @primno/dataverse-auth
```
### Usage
With connection string authentication:
```ts
import { ConnStringTokenProvider } from '@primno/dataverse-auth';
const tokenProvider = new ConnStringTokenProvider(
"AuthType=OAuth;Url=https://<Environnement>.crm.dynamics.com;UserName=<UserName>;TokenCacheStorePath=./.cache/token.json",
{
oAuth: {
// For persistent token cache on Linux/Mac to store the token in the keychain.
// Only used when TokenCacheStorePath is set.
persistence: {
serviceName: "<serviceName>", // Optional, default to "Primno.DataverseClient"
accountName: "<accountName>" // Optional, default to "MSALCache"
},
// For device code flow
deviceCodeCallback: (deviceCode) => {
console.log(deviceCode.message);
}
}
}
);
const token = await tokenProvider.getToken();
```
With OAuth:
```ts
import { OAuthTokenProvider } from '@primno/dataverse-auth';
const tokenProvider = new OAuthTokenProvider({
url: "https://<Environment>.crm.dynamics.com",
credentials: {
clientId: "51f81489-12ee-4a9e-aaae-a2591f45987d", // Sample client id
redirectUri: "app://58145B91-0C36-4500-8554-080854F2AC97", // Sample redirect uri
authorityUrl: "https://login.microsoftonline.com/common",
scope: "https://<Environment>.crm.dynamics.com/.default",
grantType: "device_code",
userName: "<Username>"
},
persistence: {
enabled: false
},
deviceCodeCallback: (deviceCode) => {
console.log(deviceCode.message);
}
});
const token = await tokenProvider.getToken();
```
dataverse-auth is provided with 2 authentication providers :
- Connection string
- OAuth2
`ConnStringTokenProvider` provides a token by using a connection string (see [Dataverse doc](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/xrm-tooling/use-connection-strings-xrm-tooling-connect) and [D365 CE on-premises doc](https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/xrm-tooling/use-connection-strings-xrm-tooling-connect?view=op-9-1)).
Only `OAuth` authentication type is supported.
The token can be persisted using the `TokenCacheStorePath` connection string parameter. To learn more about the token cache, see [Token cache](#token-cache).
```ts
const tokenProvider = new ConnStringTokenProvider(
"AuthType=OAuth;Url=https://<Environnement>.crm.dynamics.com;UserName=<UserName>;TokenCacheStorePath=./.cache/token.json",
{
oAuth: {
// For persistent token cache on Linux/Mac to store the token in the keychain.
// Only used when TokenCacheStorePath is set.
persistence: {
serviceName: "<serviceName>", // Optional, default to "Primno.DataverseClient"
accountName: "<accountName>" // Optional, default to "MSALCache"
},
// For device code flow. Show the url and code to the user.
deviceCodeCallback: (deviceCode) => {
console.log(deviceCode.message);
}
}
}
);
```
`ConnStringTokenProvider` determines which OAuth flow to use based on the parameters in the connection string.
| Parameters | Flow |
|-----------|------|
| `UserName` and `Password` | User password |
| `ClientId` and `ClientSecret` | Client credential |
| `UserName` only | Device code |
> **Note** Device code flow allows to authenticate with MFA enabled.
Examples:
| Environment | AuthType | OAuth flow | Connection string |
|-------------|----------|------------|-------------------|
| Dataverse | OAuth | Device code | `AuthType=OAuth;Url=https://<Environnement>.crm.dynamics.com;UserName=<UserName>` |
| Dataverse | OAuth | User password | `AuthType=OAuth;Url=https://<Environnement>.crm.dynamics.com;UserName=<UserName>;Password=<Password>` |
| Dataverse | OAuth | Client credential | `AuthType=OAuth;Url=https://<Environnement>.crm.dynamics.com;ClientId=<ClientId>;ClientSecret=<ClientSecret>;RedirectUri=<RedirectUri>` |
| On-premises | OAuth | User password | `AuthType=OAuth;RedirectUri=<RedirectUri>;Url=https://<D365Url>;UserName=<Domain>\<UserName>;Password=<Password>` |
`OAuthTokenProvider` provides OAuth2 authentication.
```ts
const tokenProvider = new OAuthTokenProvider(options);
```
Options definition:
```ts
interface OAuthConfig {
/**
* OAuth2 credentials
*/
credentials: {
/**
* OAuth flow
*/
grantType: "client_credential" | "password" | "device_code";
/**
* Client ID.
* @default "51f81489-12ee-4a9e-aaae-a2591f45987d" (Sample client id)
*/
clientId?: string;
/**
* Client secret for ConfidentialClientApplication.
* If set, clientCertificate is not required.
*/
clientSecret?: string;
/**
* Client certificate for ConfidentialClientApplication.
* If set, clientSecret is not required.
*/
clientCertificate?: {
thumbprint: string;
privateKey: string;
},
/**
* Authority URL (eg: https://login.microsoftonline.com/common/)
*/
authorityUrl: string;
/**
* Username for password and device_code flow.
*/
userName?: string;
/**
* Password for password flow.
*/
password?: string;
/**
* Redirect URI.
*/
redirectUri?: string;
/**
* Scope. Dataverse url suffixed with .default.
*/
scope?: string;
};
/**
* Persistence options
*/
persistence: {
/**
* Enable persistence. Default: false.
*/
enabled: true;
/**
* Cache path.
*/
cachePath: string;
/**
* Service name. Only used on Linux/MacOS to store the token in the keychain. Default: "Primno.DataverseClient"
*/
serviceName: string;
/**
* Account name. Only used on Linux/MacOS to store the token in the keychain. Default: "MSALCache"
*/
accountName: string;
};
/**
* Device code callback. Only used when grant_type is device_code.
* @param response The device code response
* @returns
*/
deviceCodeCallback?: (response: DeviceCodeResponse) => void;
/**
* Dataverse / D365 url. Eg: https://org.crm.dynamics.com
*/
url: string;
}
```
To discover the authority url, you can use the `discoverAuthority` method.
```ts
interface Authority {
authUrl: string;
resource?: string;
}
const authority: Authority = await discoverAuthority("<DataverseOrOnPremisesUrl>");
```
The token can be persisted using the `persistence` option.
It is encrypted using `DPAPI` on Windows, `libsecret` on Linux and the `Keychain` on MacOS.
If you want to query the Dataverse API, you can use [`@primno/dataverse-client`](https://www.npmjs.com/package/@primno/dataverse-client) package.
On `on-premises` environments, you may have this error :
```
Error: unable to verify the first certificate
```
To fix this issue, you can add your enterprise CA certificate to the trusted root certificate authorities by setting the `NODE_EXTRA_CA_CERTS` environment variable. See [Node.js documentation](https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file) for more information.
Thanks to Microsoft for persistence cache (msal-node-extensions).