question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Often getting 401 from Directline API within Webchat

See original GitHub issue

Screenshots

Version

Latest CDN: https://cdn.botframework.com/botframework-webchat/latest/webchat.js

Describe the bug

In an Angular application we use the bot secret to generate a new token and then pass the token to the webchat. Below are snippets of code:

(Note that some portions are omitted and replaced with ellipsis)

directline-token-provider.ts

Retrieves a secret from our web app and uses that to retrieve a token

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

//Will be modified to hold onto a token in RAM and in cookies

@Injectable({
  providedIn: 'root',
})
export class DirectlineTokenProvider {
  constructor(private httpClient: HttpClient) { }

  getDirectLineToken(conversationId: string, continueConversation: boolean) {
    //MODIFY THIS URL TO TARGET A REMOTE SOURCE
    return this.httpClient.get<DirectLineTokenResponse>('/api/configuration/directlinetoken').toPromise()
      .then(r => {
        const directlineSecret = r.directLineToken;
        console.log(`Requested continue conversation: ${!!continueConversation}`);
        if (!!continueConversation && !!conversationId) {
          console.log(`Continuing Conversation ID: ${conversationId}`);
          return this.continueConversation(directlineSecret, conversationId);
        }

        console.log('Generating new token for new conversation');
        return this.generateNewToken(directlineSecret);
      });
  }

  private continueConversation(directlineSecret: string, conversationId: string) {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${directlineSecret}`
      })
    };

    return this.httpClient.get<any>(`https://directline.botframework.com/v3/directline/conversations/${conversationId}`, httpOptions).toPromise()
      .then(r => r.token);
  }

  private generateNewToken(directlineSecret: string) {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${directlineSecret}`
      })
    };

    return this.httpClient.post<any>('https://directline.botframework.com/v3/directline/tokens/generate', null, httpOptions).toPromise()
      .then(r => r.token);
  }
}

export class DirectLineTokenResponse {
  directLineToken: string;
}

We do seem to be getting a valid token via the _https://directline.botframework.com/v3/directline/tokens/generate_ endpoint.

###We then consume the token in a component here:

  ngOnInit() {
    ...

    var params = new URLSearchParams(window.location.search);
    var continueConversation = params.get("continueConversation") === 'true';
    var conversationId = this.getCookie("conversationId");

    this.userInfoProvider.getUserInfoAsync().then((portalUser: string | PortalUser) => {
      this.portalUser = portalUser;
      return this.directlineTokenProvider.getDirectLineToken(conversationId, continueConversation);
    }).then(token => {
      console.log(`Using token: ${token}`)
      this.createConnection(token);
    });

   ...
}

Here is “createConnection”:

  createConnection(directLineToken: string) {

    var directLine = this.botWebChat.createDirectLine({ token: directLineToken });

     ...

    const store = this.botWebChat.createStore(
      {},
      ({ dispatch }) => next => action => {
        // This switch statement works. considered removing it from this post but left it for context
        switch (action.type) {
          case 'WEB_CHAT/SET_SUGGESTED_ACTIONS':
            this.addHoverText();
            break;
          case 'DIRECT_LINE/INCOMING_ACTIVITY':
            if (action.payload.activity.type === 'X_FeedbackRequest') {
              this.feedbackRequestObservable.next(action.payload);
            }
            break;
          case 'DIRECT_LINE/POST_ACTIVITY':
            action = window.simpleUpdateIn(action, ['payload', 'activity', 'channelData', 'PortalUser'], () => this.portalUser);
            break;
          default:
            break;
        }

        return next(action);
      }
    );

    this.botWebChat.renderWebChat(
      {
        directLine: Object.assign({}, directLine, {
          postActivity: function (activity) {
            activity.channelData.hostUrl = window.location.href;
            return directLine.postActivity(activity);
          }
        }),
        styleSet: styleSet,
        store
      },
      this.webchat.nativeElement
    );
    this.botWebChat["directLine"] = directLine;
    
     ...
  }

Randomly we get a 401 unauthorized response from directline when posting messages. Maybe I am missing something, but I can’t tell of a race condition where the webchat is initialized before the token is ready. This was my first instinct.

Any thoughts? We also have this issue with the following non-angular code: (Uses the actual direct line secret without negotiating for a token)

function createConnection(directLineSecret) {

     const store = window.WebChat.createStore(
          {},
         ({ dispatch }) => next => action => {
            ...
            return next(action);
        });

    window.WebChat.renderWebChat(
        {
            directLine: window.WebChat.createDirectLine({ token: directLineSecret}),
            styleSet: styleSet,
            store
        },
        document.getElementById('webchat')
    );

    ...
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
compulimcommented, Sep 21, 2019

@JIoffe I was working with engineers and we are pretty sure this is the cause:

  1. When Web Chat start conversation, it will send a request to directline.botframework.com
  2. On directline.botframework.com, when it receive “create conversation” call, it will contact the bot with a conversationUpdate activity
  3. If the activity cannot be delivered to the bot, directline.botframework.com will response to step 1 with HTTP 401, instead of the usual 502 Gateway Timeout

We looked at our server log for 401 with the conversation ID you referenced. The bot timed out on step 2, when we send conversationUpdate activity. Thus, directline.botframework.com returned 401.

As the root cause has been identified, I am closing this issue for now.

Thanks @EricDahlvang and @p-nagpal for server-side debugging. 👍🏻

1reaction
NickEricsoncommented, Oct 14, 2019

A fix was deployed world wide for this last week. Please let me know if you are still seeing this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Getting 401 errors from DirectLine when using botbuilder ...
My problem is that I'm getting 401 errors from the Directline API when my bot attempts to send a message from user to...
Read more >
API reference - Direct Line API 3.0 - Bot Service | Microsoft Learn
The request was malformed or otherwise incorrect. 401, The client isn't authorized to make the request. Often this status code occurs because ...
Read more >
Using WebChat with Azure Bot Service's Authentication
This blog covers how to use Web Chat with the Azure Bot Service's built-in authentication capability to authenticate chat users with various ...
Read more >
Microsoft/BotBuilder - Gitter
Hey All, I am trying to get direct line speech configured correctly but keep running into this "Error: Request failed with status code...
Read more >
Failed To Connect (500) To Bot Framework Using Direct Line
Consistent 500 Server Error When using postActivity function of DirectLine object the ReactWebChat component of botframework-webchat with a DirectLine ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found