Preflight fails using Angular to request token

I have…

I’m submitting a…

  • [ ] Regression (a behavior that stopped working in a new release)
  • [X ] Bug report
  • [ ] Performance issue
  • [ ] Documentation issue or request

Current behavior

Preflight fails using Angular to request token. OPTIONS fails, but POST returns a 200.

“Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost/identity-server/connect/token. (Reason: CORS request did not succeed). Status code: (null).”

request url: https://localhost/identity-server/connect/token
{
  "headers": {
    "normalizedNames": {},
    "lazyUpdate": null,
    "headers": {}
  },
  "status": 0,
  "statusText": "Unknown Error",
  "url": "https://localhost/identity-server/connect/token",
  "ok": false,
  "name": "HttpErrorResponse",
  "message": "Http failure response for https://localhost/identity-server/connect/token: 0 Unknown Error",
  "error": {
    "isTrusted": true
  }
}

Expected behavior

Can access API to retrieve token

Minimal reproduction of the problem

Spin up a local version of Squidex running on localhost
Use Firefox to bypass invalid Caddy Certification
Attempt to access the token url using Angular

        this.http
            .post(this.buildUrl('identity-server/connect/token'), body, {
                headers: new HttpHeaders({ contentType: 'application/x-www-form-urlencoded', responseType: 'json' }),
            })

Environment

App Name:

  • [X ] Self hosted with docker
  • [ ] Self hosted with IIS
  • [ ] Self hosted with other version
  • [ ] Cloud version

Version: latest

Browser:

  • [ ] Chrome (desktop)
  • [ ] Chrome (Android)
  • [ ] Chrome (iOS)
  • [X ] Firefox
  • [ ] Safari (desktop)
  • [ ] Safari (iOS)
  • [ ] IE
  • [ ] Edge

Others:

I can still not reproduce it, I have the following very simple script:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Squidex Javascript Sample</title>

    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
</head>
<body>
    <ul id="root"></ul>
	
	<script>
		const isDevelopment = false;

		const CONFIG = {
			url: 'https://cloud.squidex.io',
			appName: 'sample-blog',
			clientId: 'sample-blog:blog',
			clientSecret: 'ZxmQGgouOUmyVU4fh38QOCqKja3IH1vPu1dUx40KDec='
		};

		if (isDevelopment) {
			CONFIG.url = 'http://localhost:5000';
		}

		$(() => {

			let auth = `${CONFIG.url}/identity-server/connect/token`;

			$.ajax({
				type: 'POST',
				url: auth, 
				headers: {
					'Content-Type': 'application/x-www-form-urlencoded'
				},
				dataType: 'json',
				data: {
					grant_type: 'client_credentials',
					client_id: CONFIG.clientId,
					client_secret: CONFIG.clientSecret,
					scope: 'squidex-api'
				},
				success: authResponse => {
					let content = `${CONFIG.url}/api/content/${CONFIG.appName}/posts?$top = 10`

					$.ajax({
						type: 'GET',
						url: content,
						dataType: 'json',
						data: {},
						headers: {
							authorization: `Bearer ${authResponse.access_token}`
						},
						success: itemsResponse => {
							for (let item of itemsResponse.items) {
								$('<li>').text(`REST: ${item.data.title.iv}`).appendTo($('#root'));
							}
						}
					});

					let graphql = `${CONFIG.url}/api/content/${CONFIG.appName}/graphql`;

					const query = `
					   query {
						queryPostsContents {
						  data {
							title {
							  iv
							}
						  }
						}
					  }`;

					$.ajax({
						type: 'POST',
						url: graphql,
						contentType: 'application/json; charset=utf-8',
						dataType: 'json',
						data: JSON.stringify({ query }),
						headers: {
							authorization: `Bearer ${authResponse.access_token}`
						},
						success: itemsResponse => {
							for (let item of itemsResponse.data.queryPostsContents) {
								$('<li>').text(`GRAPHQL: ${item.data.title.iv}`).appendTo($('#root'));
							}
						}
					});
				}
			});
		});
	</script>
</body>
</html>

It works for me for the cloud. Can you also test it? It works with the this setup, but also when I create a custom blog app locally and exchange the credentials.

I’m using Angular’s httpClient, so the jQuery example doesn’t help so much. Even if I got that to work, I don’t know if it applies to my situation, but I’ll try it.

In the meanwhile, this is what I’m doing so far…

Please note, that the token endpoint is a so called simple request (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) and therefore no preflight request is needed.

There is a very easy angular example: https://github.com/Squidex/squidex-samples/tree/master/jscript/angular/sample-blog

It uses a http interceptor for authentication: https://github.com/Squidex/squidex-samples/blob/master/jscript/angular/sample-blog/src/app/services/auth.interceptor.ts

Looks like angular is adding the preflight because I’m changing the header. I was avoiding using the auth.interceptor file, but I’ll try it. I was replicating what’s in the file and it didn’t work.

Angular is not involved in that. The CORS handling is done by the browser. Which header are you talking about?

You can also get the access token manually without an interceptor, but i think this is more elegant :wink:

I was trying the manual way. I just need to create a proof of concept for a demo tomorrow. I would definitely use the interceptor in a production application. :wink:

Just copy the project and make your changes :wink:

Unfortunately, I need to show our current app working with Squidex. So making the changes to the sample wouldn’t work.

So I’ve imported the interceptor and the request for token is no longer failing. But now the request for data is blocked by CORS. :frowning:

I’m going to make sure I’ve actually implemented.

Ok, I hadn’t yet added the interceptor as a provider. But not the app won’t compile because the config file has errors. I think I only need the buildUrl from that file, so let me try running it w/out the config.ts.

Looks like CORS is back, even with the interceptor. I’m using angular version 12 and using the interceptor.

“Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost/identity-server/connect/token. (Reason: CORS request did not succeed). Status code: (null).”

Is Squidex not compatible with Angular v12? I’m going to clone the sample and bump the ng version to 12 and see if it works.

Cors has nothing to do with angular. Which version of Squidex do you use?

I know it doesn’t…not directly. But I’m not doing anything “unique” and it’s not working. Copying the file even breaks compilation…which I’m sure is related to the version difference.

I’m using the latest version of Squidex…but how to I confirm the version number?

That wasn’t it. :frowning: I’m now running the sample with Ng12 without issue. But will now try to connect it to my existing app.

Ok, so at least I’ve narrowed down the issue. the same app will not work either, when run locally. CORS error, similar to my app. Can you run the app with a local instance of
Squidex?

Yes, I tried it locally before and it works fine as well:

What build are you using? I read that we have to use https so I used the Caddy build. I see that you are not using https and you’re using port 3000.

I am using http because it does not work with https locally because of the self signed certificate. But I tried it locally on another port with a certificate as well.

I have used my local test build and 6.5

:man_facepalming:

Most of my issues were around the bad certificate that Caddy uses. If I could have just use http, that would have saved me a ton of time. The documentation says the server has to run on https. (I don’t recall where I saw it, but that’s the ONLY reason I’m running it with https).

In any event, I gave up on the local set up for now to try the cloud since that worked with the sample app. But now I’m getting an error the content type is invalid. The content type is text/plain. this is not something that I changed. I’m using the interceptor file from the sample app.