1

I have scoured every possible forum for this and somehow have not gotten my WebGL to consume my ASP.NET 4.5 REST API's.

From what I can tell it is possibly related to WebGL requiring CORS, but even enabling this I cannot get the game to communicate with my API's

So either there's something wrong with the way I have implemented global CORS settings in ASP.NET or something else is breaking. To be clear these API's are running perfectly well on Android/iOS/Windows builds and even in the editor.

What I have done so far: Installed the Microsoft CORS build as recommended by Microsoft's documentation relating to it, then added the following code to the WebAPIConfig class in Visual Studio:

public static void Register(HttpConfiguration config)
{
    config.SuppressDefaultHostAuthentication();
    config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

    // Web API routes
    config.MapHttpAttributeRoutes();

    ////new code 
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

This is also in my web.config:

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
  </customHeaders>
</httpProtocol>

I need these settings global so I used the "*" as indicated by the documentation to include all domains, method types, and headers because I use ASP.NET token authentication for my API.

Here is a code snippet that gets the token in the Unity project (just to be clear, this works on other platforms, only throws an error in a WebGL build)

public IEnumerator login()
{
    string url = API.ROUTEPATH + API.TOKEN;

    WWWForm form = new WWWForm();
    form.AddField("grant_type", "password");
    form.AddField("username", API.APIUSERNAME);
    form.AddField("password", API.APIPASSWORD);

    UnityWebRequest uwr = UnityWebRequest.Post(url, form);
    uwr.SetRequestHeader("Content-Type", "application/json");

    yield return uwr.SendWebRequest();

    try
    {
        if (uwr.isNetworkError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            APIAuthToken returnauth = JsonUtility.FromJson<APIAuthToken>(uwr.downloadHandler.text);

            if (!string.IsNullOrEmpty(returnauth.access_token))
            {
                API.hasAuth = true;
                API.token = returnauth.access_token;
                Debug.Log(returnauth.access_token);

            }

        }
    }
    catch
    {

    }
}

uwr.error produces the following, very helpful error: Unknown Error So I'm not even sure if it is CORS related, it's just my best guess based on the research I have done, but even with multiple different implementations of it I still sit with the same error. So if it's not a problem with the API's and with my Unity code please just ignore the ASP.NET code snippet.

ilkerkaran
  • 4,214
  • 3
  • 27
  • 42
Tiaan
  • 698
  • 2
  • 10
  • 32
  • Problably is this: If the preflight response did not include Access-Control-Allow-Credentials: true, or if your Access-Control-Allow-Access is set to a wildcard (*) then the cookies will not be sent and you are likely to see errors in your browser's Javascript console. Check my asnwer! (: – Qiqke Nov 18 '19 at 10:58

1 Answers1

0

cURL - A simple curl -I <endpoint> or curl -X OPTIONS -v <endpoint> can reveal a ton of information about what is happening related to CORS. It can allow you to set different origins, check preflight responses, and more.

"Let's say you have a backend API that uses cookies for session management. Your game works great when testing on your own domain, but breaks horribly once you host the files on Kongregate due to the fact that your API requests are now cross-domain and subject to strict CORS rules."

Is this your problem?

Problably on both sides if things are not set up properly will refuse to send cookies, but its good, its mean you have the control to allow what domains your sessions cookies will be sent to.

So probably you need first to configure the server to allow multiplies origins but make sure to validate the value against a whitelist so that you aren't just enabling your session cookies to be sent to any origin domain. Example on a Node Express with CORS middleware(game ID 12345) and an origin whitelist below:

 express = require('express')
var cors = require('cors')
var app = express()

var whitelist = ['https://game12345.konggames.com'];
var corsOptions = {
  credentials: true,
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
};

app.use(cors(corsOptions));
app.options('*', cors(corsOptions)); // Enable options for preflight

app.get('/', (req, res) =>  res.send('Hello World!'))
app.listen(8080, () =>  console.log(`Example app listening on port 8080!`))

cURL command to check the headers for an OPTIONS preflight request from an origin in the whitelist array:

curl -X OPTIONS -H"Origin: https://game12345.konggames.com" -v http://localhost:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: https://game12345.konggames.com
>
< HTTP/1.1 204 No Content
< X-Powered-By: Express
< Access-Control-Allow-Origin: https://game12345.konggames.com
< Vary: Origin, Access-Control-Request-Headers
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
< Content-Length: 0
< Date: Tue, 24 Sep 2019 22:04:08 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact

instruct the client to include cookies when it makes a cross-domain request,If the preflight response did not include Access-Control-Allow-Credentials: true, or if your Access-Control-Allow-Access is set to a wildcard (*) then the cookies will not be sent and you are likely to see errors in your browser's Javascript console:

Access to XMLHttpRequest at 'https://api.mygamebackend.com' from origin 'https://game54321.konggames.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Unity's UnityWebRequest and the older WWW classes use XMLHttpRequest under the hood to fetch data from remote servers. Since there is no option to set the withCredentials flag to true, we have to perform a pretty dirty hack when initializing our application in order to turn that on for the appropriate requests. In your WebGL template or generated index.html:

<script>  
   XMLHttpRequest.prototype.originalOpen = XMLHttpRequest.prototype.open;  
   var newOpen = function(_, url) {  
     var original = this.originalOpen.apply(this, arguments);  
     if (url.indexOf('https://api.mygamebackend.com') === 0) {  
       this.withCredentials = true;  
     }  

     return original;  
   }  
   XMLHttpRequest.prototype.open = newOpen;  
 </script>

This snippet of code overrides the open method of XMLHttpRequest so that we can conditionally set withCredentials equal to true when desired. Once this is in place, cross-origin cookies should begin working between the Kongregate-hosted iframe domain and the game's backend servers!


info taken from here

also looks nice for this

Qiqke
  • 486
  • 5
  • 19