{"id":15419895,"url":"https://github.com/navzam/direct-line-token-sample","last_synced_at":"2026-02-06T03:01:32.206Z","repository":{"id":40714021,"uuid":"278203393","full_name":"navzam/direct-line-token-sample","owner":"navzam","description":"Sample for obtaining and using Direct Line tokens in WebChat bots","archived":false,"fork":false,"pushed_at":"2022-12-13T06:27:55.000Z","size":286,"stargazers_count":0,"open_issues_count":14,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T03:44:40.736Z","etag":null,"topics":["bot-framework","webchat"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/navzam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-08T22:02:40.000Z","updated_at":"2020-07-23T18:15:48.000Z","dependencies_parsed_at":"2023-01-28T08:05:13.401Z","dependency_job_id":null,"html_url":"https://github.com/navzam/direct-line-token-sample","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/navzam/direct-line-token-sample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navzam%2Fdirect-line-token-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navzam%2Fdirect-line-token-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navzam%2Fdirect-line-token-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navzam%2Fdirect-line-token-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/navzam","download_url":"https://codeload.github.com/navzam/direct-line-token-sample/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navzam%2Fdirect-line-token-sample/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29147374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T02:39:25.012Z","status":"ssl_error","status_checked_at":"2026-02-06T02:37:22.784Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot-framework","webchat"],"created_at":"2024-10-01T17:27:00.985Z","updated_at":"2026-02-06T03:01:32.189Z","avatar_url":"https://github.com/navzam.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Direct Line token sample\n\nThis sample demonstrates how to implement Web Chat in a way that does not expose your Direct Line secret to the browser.\n\n## Motivation\n\n### Hiding the Web Chat secret\n\nWhen embedding Web Chat into a site, you must provide either your Direct Line secret or a Direct Line token so that Web Chat can communicate with the bot. The Direct Line secret can be used to access all of the bot's conversations, and it doesn't expire. A Direct Line token can only be used to access a single conversation, and it does expire. See the [Direct Line Authentication documentation](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication?view=azure-bot-service-4.0) for more information.\n\nTherefore, embedding Web Chat using the Direct Line secret directly is strongly discouraged because it would expose your secret on the client-side. Instead, the recommended approach is to exchange the secret for a Direct Line token on the server-side. This sample shows how to obtain and use the token.\n\n### Avoiding user impersonation\n\nWeb Chat allows you to specify a user ID on the client-side, which will be sent in activities to the bot. However, this is susceptible to user impersonation because a malicious user could modify their user ID. Since the user ID typically isn't verified, this is a security risk if the bot stores sensitive data keyed on the user ID. For example, the built-in [user authentication support in Azure Bot Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-authentication?view=azure-bot-service-4.0) associates access tokens with user IDs.\n\nTo avoid impersonation, the recommended approach is for the server to bind a user ID to the Direct Line token. Then any conversation using that token will send the bound user ID to the bot. However, if the client is going to provide the user ID to the server, it is important for the server to validate the ID somehow (see below). Otherwise, a malicious user could still modify the user ID being sent by the client.\n\nTo keep things simple, this sample generates a random user ID on the server-side and binds it to the Direct Line token. While this mitigates impersonation concerns, the downside is that users will have a different ID every time they talk to the bot. If you need a consistent and validated user ID, see the [Direct Line user token sample](https://github.com/navzam/user-direct-line-token-sample).\n\n## Architecture\n\nThis sample contains three components:\n- **The backend API** performs the Direct Line token acquisition. It generates a random user ID that will be bound to the Direct Line token.\n- **The UI** is static HTML/JS that could be hosted using any web server. It makes a POST request to the backend API and uses the resulting Direct Line token to render Web Chat.\n- **The bot** is a bare-bones bot that responds to every activity by sending the user's ID.  \n\nDepending on the scenario, the backend API could be called from a client (such as a single-page application) or a server (such as a more traditional web app). After receiving the Direct Line token, the caller can then use it to render Web Chat, and the bot will receive the randomly-generated user ID on every activity.\n\n## Code highlights\n\n### Constructing the user ID\n\nIn this sample, the user is anonymous, so the API randomly generates a user ID:\n\n\u003cdetails\u003e\u003csummary\u003eJavaScript\u003c/summary\u003e\n\n```js\n// server.js\n\nasync function generateRandomUserId() {\n    const buffer = await randomBytesAsync(16);\n    return `dl_${buffer.toString('hex')}`;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eC#\u003c/summary\u003e\n\n```csharp\n// DirectLineTokenController.cs\n\nprivate static string GenerateRandomUserId()\n{\n    byte[] tokenData = new byte[16];\n    using var rng = new RNGCryptoServiceProvider();\n    rng.GetBytes(tokenData);\n\n    return $\"dl_{BitConverter.ToString(tokenData).Replace(\"-\", \"\").ToLower()}\";\n}\n```\n\n\u003c/details\u003e\n\nThe user ID is prefixed with \"dl_\" as required by the [Direct Line token API](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication?view=azure-bot-service-4.0#generate-token).\n\n### Retrieving a user-specific Direct Line token\n\nThe API calls the Direct Line API to retrieve a Direct Line token. Notice that we pass the user ID in the body of the request:\n\n\u003cdetails\u003e\u003csummary\u003eJavaScript\u003c/summary\u003e\n\n```js\n// fetchDirectLineToken.js\n\nconst response = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', {\n    headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${secret}`,\n    },\n    method: 'post',\n    body: JSON.stringify({ user: { id: userId } })\n});\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eC#\u003c/summary\u003e\n\n```csharp\n// DirectLineTokenService.cs\n\nhttpClient.BaseAddress = new Uri(\"https://directline.botframework.com/\");\n\n...\n\nvar fetchTokenRequestBody = new { user = new { id = userId } };\n\nvar fetchTokenRequest = new HttpRequestMessage(HttpMethod.Post, \"v3/directline/tokens/generate\")\n{\n    Headers =\n    {\n        { \"Authorization\", $\"Bearer {directLineSecret}\" },\n    },\n    Content = new StringContent(JsonSerializer.Serialize(fetchTokenRequestBody), Encoding.UTF8, MediaTypeNames.Application.Json),\n};\n\nvar fetchTokenResponse = await _httpClient.SendAsync(fetchTokenRequest, cancellationToken);\n```\n\n\u003c/details\u003e\n\nThe resulting Direct Line token will be bound to the passed user ID.\n\n### Calling the API and rendering Web Chat\n\nThe UI calls the API and uses the resulting Direct Line token to render Web Chat:\n\n```js\n// index.html\n\nconst res = await fetch('http://localhost:3000/api/direct-line-token', { method: 'POST' });\nconst { token } = await res.json();\n\nwindow.WebChat.renderWebChat(\n    {\n    directLine: window.WebChat.createDirectLine({ token }),\n    },\n    document.getElementById('webchat')\n);\n```\n\nNote that we do *not* specify a user ID when initiating Web Chat. Direct Line will handle sending the user ID to the bot based on the token.\n\n## Running the sample locally\n\n### Prerequisites\n- A registered Bot Framework bot (see [documentation on registering a bot with Azure Bot Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration?view=azure-bot-service-3.0))\n\n### Run the bot\n1. Navigate to the `bot` directory.\n1. Fill in the environment variables in the `.env` file, according to the following table:\n    | Variable | Description | Example value |\n    | -------- | ----------- | ------------- |\n    | `PORT` | The port on which the bot server will run. | 3978 |\n    | `MICROSOFT_APP_ID` | The app ID of the registered Bot Framework bot. Can be found in the Azure Bot Channels Registration resource. | |\n    | `MICROSOFT_APP_SECRET` | The app secret of the registered Bot Framework Bot. Issued during registration. | |\n1. Run `npm install` to install the required dependencies.\n1. Run `npm start` to start the bot.\n1. Run `ngrok` to expose your bot to a public URL. For example:\n    ```bash\n    ngrok http -host-header=rewrite 3978\n    ```\n1. Update the messaging endpoint in your Bot Channels Registration to the ngrok URL. For example: `https://abcdef.ngrok.io/api/messages`\n\n### Run the API\n\nThe sample API is available in multiple languages. Choose one and expand the corresponding section for specific steps.\n\n\u003cdetails\u003e\u003csummary\u003eJavaScript API\u003c/summary\u003e\n\n1. Navigate to the `api/javascript` directory.\n1. Fill in the environment variables in the `.env` file. See the table below for descriptions.\n1. Run `npm install` to install the required dependencies.\n1. Run `npm start` to start the server.\n\n| Variable | Description | Example value |\n| -------- | ----------- | ------------- |\n| `PORT` | The port on which the API server will run. | 3000 |\n| `DIRECT_LINE_SECRET` | The Direct Line secret issued by Bot Framework. Can be found in the Azure Bot Channels Registration resource after enabling the Direct Line channel. |  |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eC# API\u003c/summary\u003e\n\n1. Add the required secrets to the .NET Core secret manager. See the table below for descriptions.\n    ```bash\n    cd ./api/csharp\n    dotnet user-secrets set \"DirectLine:DirectLineSecret\" \"YOUR-DIRECT-LINE-SECRET-HERE\"\n    ```\n1. (optional) Change the port specified in `./Properties/launchSettings.json`.\n1. Run `dotnet run` to start the server. (Alternatively, open and run the project in Visual Studio.)\n\n| Variable | Description | Example value |\n| -------- | ----------- | ------------- |\n| `DirectLine:DirectLineSecret` | The Direct Line secret issued by Bot Framework. Can be found in the Azure Bot Channels Registration resource after enabling the Direct Line channel. |  |\n\n\u003c/details\u003e\n\n### Run the UI\n1. Navigate to the `ui` directory.\n1. Serve `index.html` on `localhost:5500` using a web server.\n    - A quick way to get started is using the [http-server](https://www.npmjs.com/package/http-server) npm package. You can use `npx` to run it without installation:\n        ```bash\n        npx http-server ./ -p 5500\n        ```\n    - Another option is a local development server such as the [Live Server Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer).\n1. Open `http://localhost:5500` in a browser.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavzam%2Fdirect-line-token-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnavzam%2Fdirect-line-token-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavzam%2Fdirect-line-token-sample/lists"}