Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Resolved Access my cloud database via Cloud Code JavaScript

Discussion in 'Cloud Code' started by pKallv, Apr 2, 2024.

  1. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,203
    I have tried to upload a c# code to CloudScript via CLI and editor but for some reason not succeeded so I tried the elegant JavaScript generation version in CloudCode.

    As I have no experience of JavaScript I tried first creating the code based on its and then asked ChatGTP to generate the code for me.

    The problem I a addressing is to protect ClientId and ClientSecret.

    I have a c# version that works so I thought it would be easy but I get authentication problem with the JS version but not with the c# code I execute from the editor. The problem with the c# version is that there is no security when executing the REST API's directly from the code so I decided to try to use CC.

    When I try executing the CC version I get the below error.

    I there anyone that can advise a solution to this case?

    Code (CSharp):
    1. Invocation Error
    2. ------------------------------
    3. Error: Request failed with status code 401
    4.  
    5. {
    6.   "message": "Request failed with status code 401",
    7.   "name": "Error",
    8.   "request": {
    9.     "data": "{\"grant_type\":\"client_credentials\"}",
    10.     "headers": {
    11.       "Accept": "application/json, text/plain, */*",
    12.       "Content-Length": 35,
    13.       "Content-Type": "application/json",
    14.       "User-Agent": "axios/0.21.4"
    15.     },
    16.     "method": "post",
    17.     "url": "https://abc-testdb.adb.eu-stockholm-1.oraclecloudapps.com/ords/unity/oauth/token"
    18.   },
    19.   "response": {
    20.     "code": "Unauthorized",
    21.     "instance": "tag:oracle.com,2020:ecid/cc682aab72358e38ba3486aed15a8c41",
    22.     "message": "Unauthorized",
    23.     "type": "tag:oracle.com,2020:error/Unauthorized"
    24.   }
    25. }
    This is based on this JS code:

    Code (CSharp):
    1. const axios = require('axios');
    2.  
    3. module.exports = async ({ params, logger }) => {
    4.   try {
    5.     const clientId = "yyyyyyyyyy";
    6.     const clientSecret = "xxxxxxxxxxxxxxx";
    7.     const url = "abc-testdb.adb.eu-stockholm-1.oraclecloudapps.com";
    8.  
    9.     // Get access token
    10.     const tokenResponse = await axios.post(`https://${url}/ords/unity/oauth/token`, {
    11.       grant_type: 'client_credentials'
    12.     }, {
    13.       auth: {
    14.         username: clientId,
    15.         password: clientSecret
    16.       },
    17.       headers: {
    18.         'Content-Type': 'application/json'
    19.       }
    20.     });
    21.  
    22.     const accessToken = tokenResponse.data.access_token;
    23.  
    24.     // Get scene data
    25.     const sceneResponse = await axios.get(`https://${url}/ords/unity/scenes/main`, {
    26.       headers: {
    27.         Authorization: `Bearer ${accessToken}`
    28.       }
    29.     });
    30.  
    31.     const sceneData = sceneResponse.data;
    32.  
    33.     return sceneData;
    34.   } catch (error) {
    35.     logger.error(error.message);
    36.     throw error;
    37.   }
    38. };
    The c# version that works without problem looks like this:

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Text;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7. using UnityEngine.Networking;
    8.  
    9. public class ManageJSON : MonoBehaviour {
    10.  
    11.     public string url = "abc-testdb.adb.eu-stockholm-1.oraclecloudapps.com";
    12.     public string clientId = "yyyyyyyyyy";
    13.     public string clientSecret = "xxxxxxxxxxxxxxx";
    14.     public AccessToken accessToken;
    15.     public Scene scene;
    16.  
    17.     void Start() {
    18.         StartCoroutine(GetAccessToken());
    19.     }
    20.  
    21.     [Serializable]
    22.     public class AccessToken {
    23.         public string access_token;
    24.         [HideInInspector]
    25.         public string token_type;
    26.         [HideInInspector]
    27.         public int expires_in;
    28.     }
    29.  
    30.  
    31.     [Serializable]
    32.     public class Scene {
    33.         public string name;
    34.         [HideInInspector]
    35.         public string configuration;
    36.  
    37.         public void Load() {
    38.             scene = JsonUtility.FromJson<SceneConfiguration>(configuration);
    39.         }
    40.  
    41.         public string Serialize() {
    42.             return configuration = "{\"name\": \""+name+"\", \"configuration\": \""+JsonUtility.ToJson(scene).Replace("\"","\\\"")+"\"}";
    43.         }
    44.  
    45.         public SceneConfiguration scene;
    46.     }
    47.  
    48.     [Serializable]
    49.     public class SceneConfiguration {
    50.         public string region;
    51.     }
    52.  
    53.     IEnumerator GetAccessToken()
    54.     {
    55.         var plainTextBytes = Encoding.UTF8.GetBytes(clientId + ":" + clientSecret);
    56.         var encoded = Convert.ToBase64String(plainTextBytes);
    57.  
    58.         WWWForm form = new WWWForm();
    59.         form.AddField("grant_type", "client_credentials");
    60.  
    61.         Debug.Log ("Sending request");
    62.         UnityWebRequest www = UnityWebRequest.Post("https://" + url + "/ords/unity/oauth/token", form);
    63.         www.SetRequestHeader("Authorization", "Basic " + encoded);
    64.  
    65.         yield return www.SendWebRequest();
    66.  
    67.         // and check for errors
    68.         if (String.IsNullOrEmpty(www.error)) {
    69.             string resultContent = www.downloadHandler.text;
    70.             www.Dispose();
    71.  
    72.             Debug.Log(resultContent);
    73.  
    74.             accessToken = JsonUtility.FromJson<AccessToken>(resultContent);
    75.             Debug.Log("Token: " + accessToken.access_token);
    76.  
    77.             Dictionary<string,string> h = new Dictionary<string,string>();
    78.             h["Authorization"] = "Bearer " + accessToken.access_token;
    79.  
    80.             www = UnityWebRequest.Get("https://" + url + "/ords/unity/scenes/main");
    81.             www.SetRequestHeader("Authorization", "Bearer " + accessToken.access_token);
    82.  
    83.             yield return www.SendWebRequest();
    84.  
    85.             if (String.IsNullOrEmpty(www.error)) {
    86.                 resultContent = www.downloadHandler.text;
    87.                 www.Dispose();
    88.                 Debug.Log(resultContent);
    89.  
    90.                 scene = JsonUtility.FromJson<Scene>(resultContent);
    91.                 scene.Load ();
    92.  
    93.             } else {
    94.                 Debug.Log("WWW Error Scenes: " + www.error);
    95.                 www.Dispose();
    96.             }
    97.         }
    98.         else {
    99.             // something wrong!
    100.             Debug.Log("WWW Error: " + www.error);
    101.             www.Dispose();
    102.         }
    103.     }
    104.  
    105.     public void Save() {
    106.         StartCoroutine (SaveSceneConfiguration());
    107.     }
    108.  
    109.     IEnumerator SaveSceneConfiguration()
    110.     {
    111.         if (accessToken.access_token != null) {
    112.             Debug.Log ("Updating scene to: " + scene.Serialize ());
    113.  
    114.             UnityWebRequest www = UnityWebRequest.Put("https://" + url + "/ords/unity/scenes/main", Encoding.UTF8.GetBytes(scene.Serialize()));
    115.             www.SetRequestHeader("Authorization", "Bearer " + accessToken.access_token);
    116.             www.SetRequestHeader("Content-Type", "application/json");
    117.             yield return www.SendWebRequest();
    118.  
    119.             if (www.isNetworkError || www.isHttpError)
    120.             {
    121.                 Debug.Log("Error: " + www.error);
    122.             }
    123.             else
    124.             {
    125.                 Debug.Log("Update of scene complete!");
    126.             }
    127.  
    128.             www.Dispose();
    129.         }
    130.     }
    131. }
     
    Last edited: Apr 9, 2024
  2. MariusUrbelis

    MariusUrbelis

    Unity Technologies

    Joined:
    Mar 15, 2015
    Posts:
    47
    Hi! Looks like the Unauthorized response comes back from the access token endpoint you are calling. Have you attempted to replicate the headers from the C# code? Instead of using the auth parameter, try adding the Authorization Basic header to the axios request. I know the auth object should handle that, but worth a shot.

    Otherwise the docs here could help you write a Cloud Code C# module: https://docs.unity.com/ugs/en-us/ma...uides/write-modules/unity-editor#Unity_Editor
     
    pKallv likes this.
  3. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,203
    Thank you, will look into this ASAP.
     
  4. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,203
    Finally, after a lot of studying and testing, I am able to read my Autonomous Oracle Database via JS in CloudCode. Now I need to be able to call the code from the game.

    Here is the code, with some test code lins included:

    Code (CSharp):
    1. const axios = require('axios');
    2.  
    3. module.exports = async ({ params, logger }) => {
    4.   const clientId = "AAA";
    5.   const clientSecret = "BBB";
    6.   const hostname = "CCC.oraclecloudapps.com";
    7.  
    8.   const plainText = clientId + ":" + clientSecret;
    9.   const encoded = Buffer.from(plainText).toString('base64');
    10.  
    11.   const postData = "grant_type=client_credentials";
    12.  
    13.   const options = {
    14.     method: 'post',
    15.     url: `https://${hostname}/ords/unity/oauth/token`,
    16.     headers: {
    17.       'Authorization': 'Basic ' + encoded,
    18.       'Content-Type': 'application/x-www-form-urlencoded',
    19.       'Content-Length': postData.length
    20.     },
    21.     data: postData
    22.   };
    23.  
    24.   try {
    25.     const response = await axios(options);
    26.  
    27.     //logger.debug(response.message);
    28.     //logger.debug("token = "+response.data.access_token);
    29.     //logger.debug("status code = " + response.status);
    30.  
    31.     const accessToken = response.data.access_token;
    32.  
    33.     const headers = {
    34.     'Authorization': `Bearer ${accessToken}`
    35.   };
    36.  
    37.   // Second request to get scene data
    38.   const sceneResponse = await axios.get(`https://${hostname}/ords/unity/scenes/main`, { headers });
    39.  
    40.   const resultContent = sceneResponse.data;
    41.   //for (const key in resultContent) {
    42.   //  logger.debug("key = "+key);
    43.   //}
    44.   //logger.debug("links = " + resultContent.links)
    45.   logger.debug("configuration = " + resultContent.configuration)
    46.   logger.debug("NAME = " + resultContent.name)
    47.   //logger.debug("status = "+sceneResponse.status)
    48.   //logger.debug("res cont = "+resultContent);
    49.  
    50.     // Do something with accessToken here
    51.     return {
    52.        result: resultContent.configuration
    53.     };
    54.   } catch (error) {
    55.     logger.debug("Error:", error);
    56.     // Handle error here
    57.     return {
    58.       errorMessage: "Caught error"
    59.     };
    60.   }
    61. };
     
    Last edited: Apr 10, 2024