Oauth 2 3L wont work with local apps - CORS issue for authenticated apps

So you cannot authenticate local apps because of a CORS issue, this has been raised previously and not been addressed at all. The current work around is to build a proxy service between the REST API (CLOUD) and the local application.

This is no good for many who would like to build a SPA that interacts with Jira.

Does anybody know if there is an easier way to authenticate a local app with Jira Cloud REST API?

Hi @monochrome, I’m afraid this is not something that can be fixed by Atlassian, nor specific to Jira. There is a very good reason why browser have implemented this security check. You might want to read up on Cross Server Scripting (XSS) and Cross Origin Resource Sharing (CORS).

So there should be a way to set the header on jira by means of setting whitelisted domains. This is available in Jira Server. It could also be achieved by setting a domain when you setup the application under developer.atlassian.net. This would be secure and would allow apps to authenticate with Jira. For now I will settle with a chrome plugin to disable this check for everything coming and going from jira. This will at least allow me to test my app locally before I deploy. I do have a question however. If I eventually deploy this application on docker with swarm and nginx proxy will I be able to authenticate with Jira Cloud REST API. Obviously the proxy isn’t going to be on the same server as Jira. If not that cans the whole idea we have so to speak.

You can use nginx to proxy requests to the Jira Cloud REST API, which should fix the CORS problem. I would recommend also using this during development instead of the Chrome extension. This will allow you to tackle the problem prior to going live. Given that you are using Docker, this should be relatively easy to do.

Hi @remie,

I’ve setup Nginx as a proxy service with docker.

With the following config:

server {
  listen 80 default_server;
  root /usr/share/nginx/html;

  index index.html;

  server_name _;

  location / {
    try_files $uri $uri/ /index.html =404;

    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;

    if ($request_method = 'OPTIONS') {
        # Tell client that this pre-flight info is valid for 20 days
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;



It seems to add access control headers as per the below example:

* Rebuilt URL to: http://localhost:8080/
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
< HTTP/1.1 200 OK
< Server: nginx/1.15.5
< Date: Tue, 09 Oct 2018 09:45:34 GMT
< Content-Type: text/html
< Content-Length: 522
< Last-Modified: Mon, 08 Oct 2018 14:47:49 GMT
< Connection: keep-alive
< ETag: "5bbb6e15-20a"
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Headers: Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With
< Accept-Ranges: bytes

However Jira still gives a CORS error.

callback:1 Failed to load https://api.atlassian.com/oauth/token/accessible-resources: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

Any thoughts on what I’m doing wrong, any guidance would be appreciated.

@monochrome Am I correct to understand from this example that you are still connecting to api.atlassian.com from the client-side? In order to get this to work, you would need your application to connect to your nginx proxy, which is a passthrough to api.atlassian.com and which will only add the appropriate CORS headers. Something like this:

client_max_body_size 500m;
proxy_read_timeout 20s;

upstream jira {
	server api.atlassian.com;

server {
	listen 8080;

	location / {

		if ( $http_origin ~* (https?://(localhost|yourdomain.example.org)) ) {
			set $allow_origin "$http_origin";

		if ($request_method = 'OPTIONS') {
			add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
			add_header 'Access-Control-Allow-Credentials' 'true' always;
			add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,PATCH,OPTIONS' always;
			add_header 'Access-Control-Allow-Headers' 'Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, X-Auth-Token' always;
			add_header 'Access-Control-Expose-Headers' 'X-Auth-Token' always;
			add_header 'Access-Control-Max-Age' 1728000 always;
			add_header 'Content-Type' 'text/plain; charset=utf-8' always;
			add_header 'Content-Length' 0 always;
			return 204;

		if ($request_method ~* "(GET|PUT|POST|DELETE|PATCH)") {
			add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
			add_header 'Access-Control-Allow-Credentials' 'true' always;
			add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,PATCH,OPTIONS' always;
			add_header 'Access-Control-Allow-Headers' 'Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, X-Auth-Token' always;
			add_header 'Access-Control-Expose-Headers' 'X-Auth-Token' always;

		proxy_pass https://jira/;


@monochrome I ran into the same issue earlier and flagged it internally with the team(s) owning this. No ETA yet but we certainly understand the inconvinience this may cause when building apps / integration using 3LO, depending on your usecase of course. In fact, we’d prefer people not proxing data through their service if not needed for performance and reliability reasons. Feel free to throw more things at me regardinf all things 3LO. I’ll keep you all posted here on this one.

1 Like

With the proper shipping of https://jira.atlassian.com/browse/JRACLOUD-30371 the need to create a “product proxy” for the Jira 3LO APIs is no longer needed. The JIRA 3LO APIs as documented for access via “authorization code grants” (documentation here, https://developer.atlassian.com/cloud/jira/platform/oauth-2-authorization-code-grants-3lo-for-apps/) this should work as intended.

If you find any issues with this please let us know and we will address them, but with things are working as expected with a sample application. Please note that there’s no support for the implicit grant flow yet, so client-side only apps will still need for that to be added.

Hi @monochrome,

just wondering if you’ve seen the latest updates and if this eventually solved your issue? CORS config is in place for api.atlassian.com and you should be able to do your /GET calls. Unfortunately there’s still JIRA Cloud REST API (OAuth 2.0) Error 403 on POST Requests that needs to be addressed for POST operations.

Thanks for bearing with us, we’re getting there!