Pre-filling ticket forms doesn't work well with logged out users and SSO

2 Kommentare

  • Dane
    Zendesk Engineering
    Hi James,
     
    You can check the workaround here by using JWT SSO.
    0
  • James Thurley

    Hi Dane,

    Thanks for the link. As some of the comments in that thread suggest, the workaround doesn't actually address the issue: it suggests URL encoding the `return_to` parameter, but the `return_to` parameter in my scenario is created (and encoded) on Zendesk's side when it redirects from the new ticket form to the SSO flow. By the time it is received by our SSO logic, the key query string parameters have already been removed from the `return_to` URL by Zendesk.

    However, Sam (who asked the question in that thread) made a key observation: it is only query string parameters starting with `tf_` which are being removed by Zendesk, and custom query string parameters are kept intact.

    With this in mind I managed to create my own workaround: 

    When I generate a link to Zendesk, I take all the query string parameters and duplicate them, encoded, in a new custom query string parameter `form_parameters`. The original parameters still need to be there for the scenario when the user is already logged in to Zendesk.

    So this, from my original question:

    https://mycompany.zendesk.com/hc/en-us/requests/new?ticket_form_id=123&tf_1115745411613=something

    Becomes this:

    https://mycompany.zendesk.com/hc/en-us/requests/new?ticket_form_id=123&tf_1115745411613=something&form_parameters=ticket_form_id%3D123%26tf_1115745411613%3Dsomething

    When Zendesk generates the `return_to` parameter and passes it to our SSO service the `tf_1115745411613` parameter is lost but `form_parameters` parameter is not, so I simply replace the entire query string of the received `return_to` parameter with the decoded `form_parameters`.

    This restores the URL to it's original state, and I can pass that restored URL back to Zendesk as the `return_to` parameter along with the JWT data.

    In the following code you can use `createZendeskUrl` method when generating links to add the `form_parameters` query string parameter to a URL, and then use the `processRedirectUrl` during your SSO flow to restore the `return_to` URL to its original state using that parameter.

    const formParametersKey = 'form_parameters';

    export class ZendeskRedirectWorkaround {

      public static createZendeskUrl(url: string): string {
        if (!url) {
          return url;
        }

        let [start, queryString] = ZendeskRedirectWorkaround.splitAtQueryString(url);
        if (!queryString) {
          return url;
        }

        return start + '?' + queryString + '&' + formParametersKey + '=' + encodeURIComponent(queryString);
      }

      public static processRedirectUrl(url: string): string {
        if (!url) {
          return url;
        }

        let [start, queryString] = ZendeskRedirectWorkaround.splitAtQueryString(url);
        if (!queryString) {
          return url;
        }

        let queryParameters = ZendeskRedirectWorkaround.getQueryParameters(queryString);
        if (!queryParameters[formParametersKey]) {
          return url;
        }

        let formParameters = queryParameters[formParametersKey];
        let decodedParameters = decodeURIComponent(formParameters);

        return start + '?' + decodedParameters;
      }

      private static splitAtQueryString(url: string): [string, string] {
        let queryStart = url.indexOf('?');
        if (queryStart === -1) {
          return [url, ''];
        }

        return [url.slice(0, queryStart), url.slice(queryStart + 1)];
      }

      private static getQueryParameters(queryString: string): { [key: string]: string } {
        if(!queryString) {
          return {};
        }

        let result: { [key: string]: string } = {};

        let parts = queryString.split('&');
        for (let part of parts) {
          let [key, value] = part.split('=');
          result[key] = value;
        }

        return result;
      }
    }

     

    And some tests:

    describe('ZendeskRedirectWorkaround', () => {
      describe('createZendeskUrl', () => {
        it('should handle empty url', () => {
          let result = ZendeskRedirectWorkaround.createZendeskUrl('');
          expect(result).toBe('');
        });

        it('should handle URLs with no query string', () => {
          let result = ZendeskRedirectWorkaround.createZendeskUrl('https://support.foo.com/blah');
          expect(result).toBe('https://support.foo.com/blah');
        });

        it('should handle URLs with query string', () => {
          let result = ZendeskRedirectWorkaround.createZendeskUrl('https://support.foo.com/blah?a=b&c=d');
          expect(result).toBe('https://support.foo.com/blah?a=b&c=d&form_parameters=a%3Db%26c%3Dd');
        });
      });

      describe('processRedirectUrl', () => {
        it('should handle empty url', () => {
          let result = ZendeskRedirectWorkaround.processRedirectUrl('');
          expect(result).toBe('');
        });

        it('should handle URLs with no query string', () => {
          let result = ZendeskRedirectWorkaround.processRedirectUrl('https://support.foo.com/blah');
          expect(result).toBe('https://support.foo.com/blah');
        });

        it('should handle URLs with query string', () => {
          let result = ZendeskRedirectWorkaround.processRedirectUrl('https://support.foo.com/blah?x=yd&form_parameters=a%3Db%26c%3Dd');
          expect(result).toBe('https://support.foo.com/blah?a=b&c=d');
        });

        it('should handle URLs with without form parameters', () => {
          let result = ZendeskRedirectWorkaround.processRedirectUrl('https://support.foo.com/blah?a=b&c=d');
          expect(result).toBe('https://support.foo.com/blah?a=b&c=d');
        });
      });
    });

    The big questions is, why is any of this necessary?

    1

Bitte melden Sie sich an, um einen Kommentar zu hinterlassen.

Powered by Zendesk