Set up authentication with Azure AD (Entra ID)

Configure Azure AD (Entra ID) to authenticate against the Moveworks Conversations API, using Issuer + Audience and the oid claim for identity resolution.

View as Markdown

The Conversations API is in Controlled Availability. Endpoints, behaviors, and configuration surfaces may change during CA. Contact your Moveworks account team to participate.

This guide walks through configuring Azure AD (Entra ID) to authenticate against the Moveworks Conversations API.

Azure AD token claims

The Azure AD v2.0 access token claims that matter for this setup:

ClaimValue
audThe Application (client) ID or Application ID URI of your registered app.
oidThe user’s stable Azure AD object ID. This is the claim Moveworks uses to resolve the user. It is a default claim in v2.0 access tokens, so no Token configuration change is required on the app registration.
isshttps://login.microsoftonline.com/{tenant-id}/v2.0

The Moveworks credential is configured with the Application (client) ID as the Audience and reads the oid claim as the user identifier.

Prerequisites

Confirm the following with your Moveworks account team:

  • Your Moveworks tenant is provisioned for the Conversations API and your account team has provided the Bot Name (used in the Assistant-Name header on every API call).
  • You have access to the Moveworks Admin Portal (https://{org}.moveworks.com).
  • You have admin access to Azure AD (Entra ID).
  • Each user’s Azure AD object ID is already resolvable against your Moveworks user roster via your Entra / MS Graph identity integration.

Step 1: Configure the app registration in Entra ID

1

Register or open your app

In the Azure portal, go to Entra ID → App registrations → New registration (or open your existing app).

2

Set the platform and redirect URI

Under Authentication → Add a platform, choose Single-page application (SPA) and add your redirect URI there. Azure treats SPA as a public client that authenticates with PKCE alone, which is what the token request in step 3 assumes.

If your architecture requires the Web platform instead, Azure treats it as a confidential client and every token request must include a client_secret (or client_assertion). This is a valid path, but the curl in step 3.2 will not work as written — you must add client_secret to the POST body and manage that secret in your backend. If you register the app under the Web platform and omit the secret, Azure returns AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'. For most Conversations API integrations, SPA + PKCE is the simpler choice.

3

Note the Application (client) ID

Copy the Application (client) ID from the app’s Overview page. You will enter this value as the Audience on the Moveworks credential in step 2, and it is what Azure stamps as aud in access tokens issued for this app.

4

Expose an API scope

Under Expose an API, confirm the Application ID URI (Azure defaults to api://{client-id}; keep the default unless you have a reason to change it). Click Add a scope and create a delegated scope named access_as_user. Set “Who can consent?” to Admins and users so users can consent at sign-in time. Save the scope.

Then go to API permissions → Add a permission → My APIs, select this same app, expand Delegated permissions, check the scope you just created (access_as_user), and click Add permissions. Grant admin consent if your organization requires it.

This is required for Azure to issue tokens when your client requests the {client-id}/.default scope in step 3. Without an exposed API scope granted to this app, the token request fails.

5

Assign users or groups

Assign the users or groups that should have access.

This guide assumes v2.0 access tokens. If your app registration’s Manifest has accessTokenAcceptedVersion: 1 (or omitted), tokens are issued in v1 format and the iss claim will be https://sts.windows.net/{tenant-id}/ rather than the value used below. Set accessTokenAcceptedVersion: 2 in the Manifest or request tokens from the v2.0 endpoint.

Step 2: Create the JWT OAuth credential in Moveworks

In the Moveworks Admin Portal, go to https://{org}.moveworks.com/http-connectors/connector_studio/homeCredentials → create a new credential, and set the fields as follows.

FieldValue for Azure ADNotes
Credential NameA descriptive label, e.g. AzureAD-CAPIFree text.
Credential TypeJWT OAuthReveals the fields below.
Public Key valuehttps://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configurationThis field accepts a WKE (well-known endpoint) URL in place of a PEM string. Paste your tenant’s OpenID Connect discovery URL. Moveworks auto-discovers the issuer and fetches the JWKS signing keys from it, so you never paste a static key.
AudienceThe Application (client) ID GUID you noted in step 1, e.g. a1b2c3d4-e5f6-7890-abcd-ef1234567890Enter the exact aud value your tokens carry. If your tokens carry the Application ID URI, e.g. api://<client-id>, enter that instead.
Issuerhttps://login.microsoftonline.com/{tenant-id}/v2.0The iss claim your tokens carry. Together with Audience, it uniquely identifies this credential.
Identifier TypeIdPTells Moveworks to resolve the identifier claim through an identity integration rather than as a raw email or record ID.
Integration IDconversations_rest_apiRequired when Identifier Type is IdP. Moveworks matches the oid claim against the user’s Conversations API channel entry on their profile.
Identifier ClaimoidThe claim Moveworks reads to identify the user. Azure’s sub is a pairwise GUID and is not usable for identity resolution, so use oid, which matches the object ID synced from Entra.

The Audience value must exactly match the aud claim your Azure tokens actually carry. That value depends on your app registration and token version:

  • v2.0 tokens with the default Application ID URI: aud is typically the Application (client) ID GUID (the common case).
  • v1.0 tokens: aud is typically the Application ID URI (api://<client-id>).
  • Custom Application ID URI: aud matches whatever value you set.

Recommended: obtain a test token in step 3 first, decode it at jwt.ms, and paste the exact aud value from the decoded token into this field before saving the credential. If the values don’t match, the token exchange fails with invalid_audience.

Save the credential.

Step 3: Request an access token from Azure AD

Your client application obtains an Azure access token via the OAuth 2.0 Authorization Code + PKCE flow. This is a two-hop flow: your app redirects the user’s browser to Azure to sign in, then exchanges the returned authorization code for an access token.

The Azure endpoints

Both endpoints are tenant-specific. Substitute your Entra tenant ID (a GUID).

PurposeURL
Authorization (browser redirect for sign-in)https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize
Token (exchange the authorization code)https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token

Step 3.1: Redirect the user to sign in

Construct the authorization URL with the following query parameters and redirect the user’s browser to it.

ParameterValue
client_idYour Application (client) ID
response_typecode
redirect_uriThe redirect URI you configured on the app registration
response_modequery
scope{client-id}/.default (see note below)
stateA CSRF token you generate and validate on return
code_challengePKCE code challenge (base64url of SHA-256 of the verifier)
code_challenge_methodS256

Example:

https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize?
client_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890
&response_type=code
&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fauth%2Fcallback
&response_mode=query
&scope=a1b2c3d4-e5f6-7890-abcd-ef1234567890%2F.default
&state=<csrf-token>
&code_challenge=<pkce-challenge>
&code_challenge_method=S256

The scope parameter must be {client-id}/.default (using your Application (client) ID). This is what causes Azure to issue a token whose aud claim equals your client ID, matching the Audience registered on the Moveworks credential. Requesting a different scope (for example, openid profile email alone) causes Azure to issue a token intended for a different resource and Moveworks will reject the exchange with invalid_audience.

After the user signs in, Azure redirects the browser to your redirect_uri with code and state query parameters. Validate state matches what you sent, then use code in the next step.

Step 3.2: Exchange the authorization code for an access token

POST to the token endpoint with the authorization code, PKCE verifier, and application details.

$curl -X POST "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token" \
> -H "Content-Type: application/x-www-form-urlencoded" \
> --data-urlencode "client_id=<APPLICATION_CLIENT_ID>" \
> --data-urlencode "scope=<APPLICATION_CLIENT_ID>/.default" \
> --data-urlencode "code=<AUTHORIZATION_CODE>" \
> --data-urlencode "redirect_uri=<REDIRECT_URI>" \
> --data-urlencode "grant_type=authorization_code" \
> --data-urlencode "code_verifier=<PKCE_VERIFIER>"

A successful response returns an access_token (an Azure-issued JWT). This is what you pass to Moveworks in step 4.

Manual testing tips

For testing the setup without wiring up a full client:

  • Use OAuth Debugger or Postman’s OAuth 2.0 support to run the Authorization Code + PKCE flow interactively against your Entra app registration. Both let you paste in the endpoints, client ID, scope, and redirect URI, and hand back the access token.
  • Alternatively, use the Microsoft Graph Explorer if you just want to verify a user can sign in and see what claims their token carries.

Decode the returned access token (for example, at jwt.ms) and confirm the claims before moving to step 4:

  • aud equals the Application (client) ID you registered as the Audience.
  • iss equals https://login.microsoftonline.com/{your-tenant-id}/v2.0.
  • oid is present and matches the object ID Moveworks has for the test user.

Step 4: Validate end to end

The examples below use https://api.moveworks.ai, which is only correct for orgs on the US Production data center. Replace it with the base URL for your data center from the Base URLs table (for example, https://api.am-eu-central.moveworks.ai for EU). Requests to the wrong host return 404 or invalid_audience.

4.1 Exchange for a Moveworks token

Pass the Azure-issued token to the Moveworks token endpoint:

$curl -X POST "https://api.moveworks.ai/oauth/v1/token" \
> -H "Content-Type: application/x-www-form-urlencoded" \
> --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
> --data-urlencode "assertion=<AZURE_ACCESS_TOKEN>"

A successful response returns a Moveworks access token (valid ~1 hour).

4.2 Test the API

$curl -X POST "https://api.moveworks.ai/assistant/v1/conversations" \
> -H "Content-Type: application/json" \
> -H "Assistant-Name: <YOUR_BOT_NAME>" \
> -H "Authorization: Bearer <MW_ACCESS_TOKEN>" \
> -d '{"title": "Test conversation"}'

A 201 with a conversation_id confirms the integration works end to end.

Summary

Credential fieldAzure AD value
Public Key valueWKE URL: https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration
AudienceApplication (client) ID GUID from the Entra app registration
Issuerhttps://login.microsoftonline.com/{tenant-id}/v2.0
Identifier TypeIdP
Integration IDconversations_rest_api
Identifier Claimoid
Entra sideNo claim configuration required. oid is a default claim in v2.0 access tokens, and no custom claims are needed.

For interaction patterns (polling and streaming) and the full API contract, see the Conversations API reference.