Recent searches


No recent searches

James Thurley's Avatar

James Thurley

Joined Jun 22, 2022

·

Last activity Jul 27, 2022

Following

0

Followers

0

Total activity

6

Votes

2

Subscription

1

ACTIVITY OVERVIEW

Latest activity by James Thurley

James Thurley commented,

CommentTicket customization

For those having the same issue as Sam with `tf_*` query string parameters being removed from the `return_to` URL by Zendesk during the SSO flow, I asked the same question separately at the following URL and have also created a workaround which I've posted as a comment there:

https://support.zendesk.com/hc/en-us/community/posts/4703281675418-Pre-filling-ticket-forms-doesn-t-work-well-with-logged-out-users-and-SSO?page=1#community_comment_4762283979034

 

View comment · Posted Jul 13, 2022 · James Thurley

0

Followers

1

Vote

0

Comments


James Thurley commented,

Community comment Q&A - Tickets and email

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?

View comment · Edited Jul 13, 2022 · James Thurley

0

Followers

1

Vote

0

Comments


James Thurley created a post,

Post Q&A - Tickets and email

We have links from our (non-zendesk) site to help our users create tickets on Zendesk, and these links will pre-fill certain parts of the ticket form to give additional useful context, using query string parameters as described here.

However, if the user is not logged into Zendesk then the redirect to authenticate will lose the query string parameters which pre-populate the form. This means the user gets a very slick sign-in experience, but ends up with an unexpectedly empty form.

So for example, if the link on our site takes the user to:

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

Zendesk immediately redirects to:

https://mycompany.zendesk.com/hc/en-gb/restricted?return_to=https%3A%2F%2Fmycompany.zendesk.com%2Fhc%2Fen-gb%2Frequests%2Fnew%3Fticket_form_id%3D123

The next redirect is to our SSO sign-in page, however you can see it has already lost the `tf_1115745411613=something` query string parameter in the redirect to the `restricted` page. It remains missing all the way though the SSO process until the user is sent back to the original URL, which is now no longer exactly the original URL as it is missing query string parameters. 

What I need is for the query string parameters to be preserved through the SSO process.

Is there a way to achieve this currently?

 

Edited Jun 23, 2022 · James Thurley

1

Follower

8

Votes

7

Comments