# Directory Structure
```
├── .gitignore
├── LICENSE
├── NOTES.md
├── package.json
├── README.md
├── screenshot.png
├── scripts
│ └── create-service-account.js
├── src
│ ├── auth.ts
│ ├── config.ts
│ ├── server.ts
│ └── tools
│ ├── common.ts
│ ├── get-accounts.ts
│ ├── get-folder-contents.ts
│ ├── get-issue-comments.ts
│ ├── get-issue-root-causes.ts
│ ├── get-issue-types.ts
│ ├── get-issues.ts
│ ├── get-item-versions.ts
│ ├── get-projects.ts
│ └── index.ts
├── tsconfig.json
└── yarn.lock
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
node_modules
build
.env
*.log
.DS_Store
Thumbs.db
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
> IMPORTANT: This project has been moved to https://github.com/autodesk-platform-services/aps-mcp-server-nodejs.
---
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
# aps-mcp-server
Experimental [Model Context Protocol](https://modelcontextprotocol.io) server build with Node.js, providing access to [Autodesk Platform Services](https://aps.autodesk.com) API, with fine-grained access control using the new _Secure Service Accounts_ feature.

[YouTube Video](https://youtu.be/6DRSR9HlIds)
## Development
### Prerequisites
- [Node.js](https://nodejs.org)
- [APS app credentials](https://aps.autodesk.com/en/docs/oauth/v2/tutorials/create-app) (must be a _Server-to-Server_ application type)
- [Provisioned access to ACC or BIM360](https://get-started.aps.autodesk.com/#provision-access-in-other-products)
### Setup
#### Server
- Clone this repository
- Install dependencies: `yarn install`
- Build the TypeScript code: `yarn run build`
- Create a _.env_ file in the root folder of this project, and add your APS credentials:
- `APS_CLIENT_ID` - your APS application client ID
- `APS_CLIENT_SECRET` - your APS application client secret
- Create a new service account: `npx create-service-account <username> <first name> <last name>`, for example, `npx create-service-account ssa-test-user John Doe`
- This script will output a bunch of environment variables with information about the new account:
- `APS_SA_ID` - your service account ID
- `APS_SA_EMAIL` - your service account email
- `APS_SA_KEY_ID` - your service account key ID
- `APS_SA_PRIVATE_KEY` - your service account private key
- Add these environment variables to your _.env_ file
#### Autodesk Construction Cloud
- Register your APS application client ID as a custom integration
- Invite the service account email as a new member to your ACC project(s)
### Use with Inspector
- Run the [Model Context Protocol Inspector](https://modelcontextprotocol.io/docs/tools/inspector): `yarn run inspect`
- Open http://localhost:5173
- Hit `Connect` to start this MCP server and connect to it
### Use with Claude Desktop
- Make sure you have [Claude Desktop](https://claude.ai/download) installed
- Create a Claude Desktop config file if you don't have one yet:
- On macOS: _~/Library/Application Support/Claude/claude\_desktop\_config.json_
- On Windows: _%APPDATA%\Claude\claude\_desktop\_config.json_
- Add this MCP server to the config, using the absolute path of the _build/server.js_ file on your system, for example:
```json
{
"mcpServers": {
"autodesk-platform-services": {
"command": "node",
"args": [
"/absolute/path/to/aps-mcp-server/build/server.js"
]
}
}
}
```
- Open Claude Desktop, and try some of the following test prompt:
- What ACC projects do I have access to?
- Give me a visual dashboard of all issues in project XYZ
> For more details on how to add MCP servers to Claude Desktop, see the [official documentation](https://modelcontextprotocol.io/quickstart/user).
### Use with Visual Studio Code & Copilot
- Make sure you have [enabled MCP servers in Visual Studio Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_enable-mcp-support-in-vs-code)
- Create _.vscode/mcp.json_ file in your workspace, and add the following JSON to it:
```json
{
"servers": {
"Autodesk Platform Services": {
"type": "stdio",
"command": "node",
"args": [
"/absolute/path/to/aps-mcp-server/build/server.js"
]
}
}
}
```
> For more details on how to add MCP servers to Visual Studio Code, see the [documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
### Use with Cursor
- Create _.cursor/mcp.json_ file in your workspace, and add the following JSON to it:
```json
{
"mcpServers": {
"Autodesk Platform Services": {
"command": "node",
"args": [
"/Users/brozp/Code/Temp/aps-mcp-server-node/build/server.js"
]
}
}
}
```
> For more details on how to add MCP servers to Cursor, see the [documentation](https://docs.cursor.com/context/model-context-protocol)
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
```
--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------
```typescript
export { getAccounts } from "./get-accounts.js";
export { getProjects } from "./get-projects.js";
export { getFolderContents } from "./get-folder-contents.js";
export { getItemVersions } from "./get-item-versions.js";
export { getIssues } from "./get-issues.js";
export { getIssueTypes } from "./get-issue-types.js";
export { getIssueRootCauses } from "./get-issue-root-causes.js";
export { getIssueComments } from "./get-issue-comments.js";
```
--------------------------------------------------------------------------------
/NOTES.md:
--------------------------------------------------------------------------------
```markdown
# TODO
## Authentication
Currently there's a [draft proposal](https://spec.modelcontextprotocol.io/specification/draft/basic/authorization/#22-basic-oauth-21-authorization) for adding OAuth 2.0 to Model Context Protocol. For now we'll use Secure Service Accounts.
## Fetch
For some reason, Claude Desktop is not able to use this server when it uses the built-in [fetch](https://nodejs.org/dist/latest-v22.x/docs/api/globals.html#fetch) method, perhaps because it's using an older version of Node.js. For now we're using the [node-fetch](https://www.npmjs.com/package/node-fetch) NPM module.
```
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
```typescript
import path from "node:path";
import url from "node:url";
import dotenv from "dotenv";
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config({ path: path.resolve(__dirname, "..", ".env") });
const { APS_CLIENT_ID, APS_CLIENT_SECRET, APS_SA_ID, APS_SA_EMAIL, APS_SA_KEY_ID } = process.env;
const APS_SA_PRIVATE_KEY = process.env.APS_SA_PRIVATE_KEY ? Buffer.from(process.env.APS_SA_PRIVATE_KEY, "base64").toString("utf-8") : undefined;
export {
APS_CLIENT_ID,
APS_CLIENT_SECRET,
APS_SA_ID,
APS_SA_EMAIL,
APS_SA_KEY_ID,
APS_SA_PRIVATE_KEY
}
```
--------------------------------------------------------------------------------
/src/tools/get-accounts.ts:
--------------------------------------------------------------------------------
```typescript
import { DataManagementClient } from "@aps_sdk/data-management";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {};
export const getAccounts: Tool<typeof schema> = {
title: "get-accounts",
description: "List all available Autodesk Construction Cloud accounts",
schema,
callback: async () => {
const accessToken = await getAccessToken(["data:read"]);
const dataManagementClient = new DataManagementClient();
const hubs = await dataManagementClient.getHubs({ accessToken });
if (!hubs.data) {
throw new Error("No accounts found");
}
return {
content: hubs.data.map((hub) => ({
type: "text",
text: JSON.stringify({ id: hub.id, name: hub.attributes?.name })
}))
};
}
};
```
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import * as tools from "./tools/index.js";
import { APS_CLIENT_ID, APS_CLIENT_SECRET, APS_SA_ID, APS_SA_EMAIL, APS_SA_KEY_ID, APS_SA_PRIVATE_KEY } from "./config.js";
if (!APS_CLIENT_ID || !APS_CLIENT_SECRET || !APS_SA_ID || !APS_SA_EMAIL || !APS_SA_KEY_ID || !APS_SA_PRIVATE_KEY) {
console.error("Missing one or more required environment variables: APS_CLIENT_ID, APS_CLIENT_SECRET, APS_SA_ID, APS_SA_EMAIL, APS_SA_KEY_ID, APS_SA_PRIVATE_KEY");
process.exit(1);
}
const server = new McpServer({ name: "autodesk-platform-services", version: "0.0.1" });
for (const tool of Object.values(tools)) {
server.tool(tool.title, tool.description, tool.schema, tool.callback);
}
try {
await server.connect(new StdioServerTransport());
} catch (err) {
console.error("Server error:", err);
}
```
--------------------------------------------------------------------------------
/src/tools/get-item-versions.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { DataManagementClient } from "@aps_sdk/data-management";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
projectId: z.string().nonempty(),
itemId: z.string().nonempty()
};
export const getItemVersions: Tool<typeof schema> = {
title: "get-item-versions",
description: "List all versions of a document in Autodesk Construction Cloud",
schema,
callback: async ({ projectId, itemId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const dataManagementClient = new DataManagementClient();
const versions = await dataManagementClient.getItemVersions(projectId, itemId, { accessToken });
if (!versions.data) {
throw new Error("No versions found");
}
return {
content: versions.data.map((version) => ({ type: "text", text: JSON.stringify(version) }))
};
}
};
```
--------------------------------------------------------------------------------
/src/tools/get-issues.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { IssuesClient } from "@aps_sdk/construction-issues";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
projectId: z.string().nonempty()
};
export const getIssues: Tool<typeof schema> = {
title: "get-issues",
description: "List all available projects in an Autodesk Construction Cloud account",
schema,
callback: async ({ projectId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const issuesClient = new IssuesClient();
projectId = projectId.replace("b.", ""); // the projectId should not contain the "b." prefix
const issues = await issuesClient.getIssues(projectId, { accessToken });
if (!issues.results) {
throw new Error("No issues found");
}
return {
content: issues.results.map((issue) => ({ type: "text", text: JSON.stringify(issue) }))
};
}
};
```
--------------------------------------------------------------------------------
/src/tools/get-issue-types.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { IssuesClient } from "@aps_sdk/construction-issues";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
projectId: z.string().nonempty()
};
export const getIssueTypes: Tool<typeof schema> = {
title: "get-issue-types",
description: "List all issue types in an Autodesk Construction Cloud project",
schema,
callback: async ({ projectId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const issuesClient = new IssuesClient();
projectId = projectId.replace("b.", ""); // the projectId should not contain the "b." prefix
const issueTypes = await issuesClient.getIssuesTypes(projectId, { accessToken });
if (!issueTypes.results) {
throw new Error("No issue types found");
}
return {
content: issueTypes.results.map((issue) => ({ type: "text", text: JSON.stringify(issue) }))
};
}
};
```
--------------------------------------------------------------------------------
/src/tools/get-projects.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { DataManagementClient } from "@aps_sdk/data-management";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
accountId: z.string().nonempty()
};
export const getProjects: Tool<typeof schema> = {
title: "get-projects",
description: "List all available projects in an Autodesk Construction Cloud account",
schema,
callback: async ({ accountId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const dataManagementClient = new DataManagementClient();
const projects = await dataManagementClient.getHubProjects(accountId, { accessToken });
if (!projects.data) {
throw new Error("No projects found");
}
return {
content: projects.data.map((project) => ({
type: "text",
text: JSON.stringify({ id: project.id, name: project.attributes?.name })
}))
};
}
};
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "aps-mcp-server",
"version": "0.0.1",
"type": "module",
"private": true,
"description": "Experimental [Model Context Protocol](https://modelcontextprotocol.io) server providing access to [Autodesk Platform Services](https://aps.autodesk.com) API.",
"author": "Petr Broz <[email protected]>",
"bin": {
"aps-mcp-server": "./build/server.js",
"create-service-account": "./scripts/create-service-account.js"
},
"scripts": {
"build": "tsc",
"inspect": "mcp-inspector node ./build/server.js"
},
"files": [
"build"
],
"dependencies": {
"@aps_sdk/authentication": "^1.0.0",
"@aps_sdk/construction-issues": "^1.1.0",
"@aps_sdk/data-management": "^1.0.1",
"@modelcontextprotocol/sdk": "^1.7.0",
"dotenv": "^16.4.7",
"jsonwebtoken": "^9.0.2",
"node-fetch": "^3.3.2",
"zod": "^3.24.2"
},
"devDependencies": {
"@modelcontextprotocol/inspector": "^0.6.0",
"@types/jsonwebtoken": "^9.0.9",
"@types/node": "^22.13.10",
"typescript": "^5.8.2"
}
}
```
--------------------------------------------------------------------------------
/src/tools/get-issue-comments.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { IssuesClient } from "@aps_sdk/construction-issues";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
projectId: z.string().nonempty(),
issueId: z.string().nonempty()
};
export const getIssueComments: Tool<typeof schema> = {
title: "get-issue-comments",
description: "Retrieves a list of comments associated with an issue in Autodesk Construction Cloud.",
schema,
callback: async ({ projectId, issueId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const issuesClient = new IssuesClient();
projectId = projectId.replace("b.", ""); // the projectId should not contain the "b." prefix
const comments = await issuesClient.getComments(projectId, issueId, { accessToken})
if (!comments.results) {
throw new Error("No comments found");
}
return {
content: comments.results.map((comment) => ({ type: "text", text: JSON.stringify(comment) }))
};
}
};
```
--------------------------------------------------------------------------------
/src/tools/get-issue-root-causes.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { IssuesClient } from "@aps_sdk/construction-issues";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
projectId: z.string().nonempty()
};
export const getIssueRootCauses: Tool<typeof schema> = {
title: "get-issue-root-causes",
description: "Retrieves a list of supported root cause categories and root causes that you can allocate to an issue in Autodesk Construction Cloud.",
schema,
callback: async ({ projectId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const issuesClient = new IssuesClient();
projectId = projectId.replace("b.", ""); // the projectId should not contain the "b." prefix
const rootCauses = await issuesClient.getRootCauseCategories(projectId, { accessToken });
if (!rootCauses.results) {
throw new Error("No root causes found");
}
return {
content: rootCauses.results.map((rootCause) => ({ type: "text", text: JSON.stringify(rootCause) }))
};
}
};
```
--------------------------------------------------------------------------------
/src/tools/common.ts:
--------------------------------------------------------------------------------
```typescript
import { ZodRawShape } from "zod";
import { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
import { APS_CLIENT_ID, APS_CLIENT_SECRET, APS_SA_ID, APS_SA_KEY_ID, APS_SA_PRIVATE_KEY } from "../config.js";
import { getServiceAccountAccessToken } from "../auth.js";
export interface Tool<Args extends ZodRawShape> {
title: string;
description: string;
schema: Args;
callback: ToolCallback<Args>;
}
const credentialsCache = new Map<string, { accessToken: string, expiresAt: number }>();
export async function getAccessToken(scopes: string[]): Promise<string> {
const cacheKey = scopes.join("+");
let credentials = credentialsCache.get(cacheKey);
if (!credentials || credentials.expiresAt < Date.now()) {
const { access_token, expires_in } = await getServiceAccountAccessToken(APS_CLIENT_ID!, APS_CLIENT_SECRET!, APS_SA_ID!, APS_SA_KEY_ID!, APS_SA_PRIVATE_KEY!, scopes);
credentials = {
accessToken: access_token,
expiresAt: Date.now() + expires_in * 1000
};
credentialsCache.set(cacheKey, credentials);
}
return credentials.accessToken;
}
```
--------------------------------------------------------------------------------
/src/tools/get-folder-contents.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from "zod";
import { DataManagementClient } from "@aps_sdk/data-management";
import { getAccessToken } from "./common.js";
import type { Tool } from "./common.js";
const schema = {
accountId: z.string().nonempty(),
projectId: z.string().nonempty(),
folderId: z.string().optional()
};
export const getFolderContents: Tool<typeof schema> = {
title: "get-folder-contents",
description: "List contents of a project or a specific subfolder in Autodesk Construction Cloud",
schema,
callback: async ({ accountId, projectId, folderId }) => {
// TODO: add pagination support
const accessToken = await getAccessToken(["data:read"]);
const dataManagementClient = new DataManagementClient();
const contents = folderId
? await dataManagementClient.getFolderContents(projectId, folderId, { accessToken })
: await dataManagementClient.getProjectTopFolders(accountId, projectId, { accessToken });
if (!contents.data) {
throw new Error("No contents found");
}
return {
content: contents.data.map((item) => ({ type: "text", text: JSON.stringify(item) }))
};
}
};
```
--------------------------------------------------------------------------------
/scripts/create-service-account.js:
--------------------------------------------------------------------------------
```javascript
#!/usr/bin/env node
import process from "node:process";
import { getClientCredentialsAccessToken, createServiceAccount, createServiceAccountPrivateKey } from "../build/auth.js";
import { APS_CLIENT_ID, APS_CLIENT_SECRET } from "../build/config.js";
if (!APS_CLIENT_ID || !APS_CLIENT_SECRET) {
console.error("Please set the APS_CLIENT_ID and APS_CLIENT_SECRET environment variables.");
process.exit(1);
}
const [,, userName, firstName, lastName] = process.argv;
if (!userName || !firstName || !lastName) {
console.error("Usage: node create-service-account.js <userName> <firstName> <lastName>");
console.error("Example: node create-service-account.js test-robot Rob Robot");
process.exit(1);
}
try {
const credentials = await getClientCredentialsAccessToken(APS_CLIENT_ID, APS_CLIENT_SECRET, ["application:service_account:write", "application:service_account_key:write"]);
const { serviceAccountId, email } = await createServiceAccount(userName, firstName, lastName, credentials.access_token);
const { kid, privateKey } = await createServiceAccountPrivateKey(serviceAccountId, credentials.access_token);
console.log("Service account created successfully!");
console.log("Invite the following user to your project:", email);
console.log("Include the following environment variables to your application:");
console.log(`APS_SA_ID="${serviceAccountId}"`);
console.log(`APS_SA_EMAIL="${email}"`);
console.log(`APS_SA_KEY_ID="${kid}"`);
console.log(`APS_SA_PRIVATE_KEY="${Buffer.from(privateKey).toString("base64")}"`);
} catch (err) {
console.error(err);
process.exit(1);
}
```
--------------------------------------------------------------------------------
/src/auth.ts:
--------------------------------------------------------------------------------
```typescript
import fetch from "node-fetch";
import jwt from "jsonwebtoken";
interface Credentials {
access_token: string;
token_type: string;
expires_in: number;
}
/**
* Generates an access token for APS using specific grant type.
*
* @param clientId The client ID provided by Autodesk.
* @param clientSecret The client secret provided by Autodesk.
* @param grantType The grant type for the access token.
* @param scopes An array of scopes for which the token is requested.
* @param assertion The JWT assertion for the access token.
* @returns A promise that resolves to the access token response object.
* @throws If the request for the access token fails.
*/
async function getAccessToken(clientId: string, clientSecret: string, grantType: string, scopes: string[], assertion?: string): Promise<Credentials> {
const headers = {
"Accept": "application/json",
"Authorization": `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded"
};
const body = new URLSearchParams({
"grant_type": grantType,
"scope": scopes.join(" ")
});
if (assertion) {
body.append("assertion", assertion);
}
const response = await fetch("https://developer.api.autodesk.com/authentication/v2/token", { method: "POST", headers, body });
if (!response.ok) {
throw new Error(`Could not generate access token: ${await response.text()}`);
}
const credentials = await response.json() as Credentials;
return credentials;
}
/**
* Creates a JWT assertion for OAuth 2.0 authentication.
*
* @param clientId The client ID of the application.
* @param serviceAccountId The service account ID.
* @param serviceAccountKeyId The key ID of the service account.
* @param serviceAccountPrivateKey The private key of the service account.
* @param scopes The scopes for the access token.
* @returns The signed JWT assertion.
*/
function createAssertion(clientId: string, serviceAccountId: string, serviceAccountKeyId: string, serviceAccountPrivateKey: string, scopes: string[]) {
// TODO: validate inputs
const payload = {
iss: clientId,
sub: serviceAccountId,
aud: "https://developer.api.autodesk.com/authentication/v2/token",
exp: Math.floor(Date.now() / 1000) + 300, // 5 minutes
scope: scopes
};
const options = {
algorithm: "RS256" as jwt.Algorithm,
header: { alg: "RS256", kid: serviceAccountKeyId }
};
return jwt.sign(payload, serviceAccountPrivateKey, options);
}
/**
* Generates an access token for APS using client credentials ("two-legged") flow.
*
* @param clientId The client ID provided by Autodesk.
* @param clientSecret The client secret provided by Autodesk.
* @param scopes An array of scopes for which the token is requested.
* @returns A promise that resolves to the access token response object.
* @throws If the request for the access token fails.
*/
export async function getClientCredentialsAccessToken(clientId: string, clientSecret: string, scopes: string[]) {
return getAccessToken(clientId, clientSecret, "client_credentials", scopes);
}
/**
* Retrieves an access token for a service account using client credentials and JWT assertion.
*
* @param clientId The client ID for the OAuth application.
* @param clientSecret The client secret for the OAuth application.
* @param serviceAccountId The ID of the service account.
* @param serviceAccountKeyId The key ID of the service account.
* @param serviceAccountPrivateKey The private key of the service account.
* @param scopes An array of scopes for the access token.
* @returns A promise that resolves to the access token response object.
* @throws If the access token could not be retrieved.
*/
export async function getServiceAccountAccessToken(clientId: string, clientSecret: string, serviceAccountId: string, serviceAccountKeyId: string, serviceAccountPrivateKey: string, scopes: string[]) {
const assertion = createAssertion(clientId, serviceAccountId, serviceAccountKeyId, serviceAccountPrivateKey, scopes);
return getAccessToken(clientId, clientSecret, "urn:ietf:params:oauth:grant-type:jwt-bearer", scopes, assertion);
}
/**
* Creates a new service account with the given name.
*
* @param name The name of the service account to create (must be between 5 and 64 characters long).
* @param firstName The first name of the service account.
* @param lastName The last name of the service account.
* @param accessToken The access token for authentication.
* @returns A promise that resolves to the created service account response.
* @throws If the request to create the service account fails.
*/
export async function createServiceAccount(name: string, firstName: string, lastName: string, accessToken: string) {
const headers = {
"Accept": "application/json",
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
};
const body = JSON.stringify({ name, firstName, lastName });
const response = await fetch("https://developer.api.autodesk.com/authentication/v2/service-accounts", { method: "POST", headers, body });
if (!response.ok) {
throw new Error(`Could not create service account: ${await response.text()}`);
}
return response.json();
}
/**
* Creates a private key for a given service account.
*
* @param serviceAccountId - The ID of the service account for which to create a private key.
* @param accessToken - The access token used for authorization.
* @returns A promise that resolves to the private key details.
* @throws If the request to create the private key fails.
*/
export async function createServiceAccountPrivateKey(serviceAccountId: string, accessToken: string) {
const headers = {
"Accept": "application/json",
"Authorization": `Bearer ${accessToken}`
};
const response = await fetch(`https://developer.api.autodesk.com/authentication/v2/service-accounts/${serviceAccountId}/keys`, { method: "POST", headers });
if (!response.ok) {
throw new Error(`Could not create service account private key: ${await response.text()}`);
}
return response.json();
}
```