custom authentication (PlayFab -> GameSparks)

System
System admin
This discussion was created from comments split from: GameSparks integration: How supported?.

Comments

  • xblade724
    xblade724
    edited August 2017
    Thanks @Markus -- When you say via HTTP [webhooks], you're saying this is to replace event streams and such, correct? Nice :thumbsup:

    Few more related questions:

    -1-

    I currently use this for logging in via PlayFab to connect to Photon:
    // Need some auth values (before we connect)
    // Set username via PF display name
    PhotonNetwork.playerName = displayName;
    
    AuthenticationValues customAuth = new AuthenticationValues();
    
    // Important: Select authentication type (how / where the auth is verified)
    customAuth.AuthType = CustomAuthenticationType.Custom;
    
    // The demo authentication-service expects values for "username" and token
    customAuth.AddAuthParameter("username", pfid);
    customAuth.AddAuthParameter("token", _photonAuthTicket);
    
    // Set UserId to find friends later (by pfid)
    customAuth.UserId = pfid;
    
    // Set the values
    PhotonNetwork.AuthValues = customAuth;
    How can I still use a UserId and Username if I can't custom login with PlayFab anymore? Can I still do custom auth and just exclude the token? Can playerName still be set np too?

    Just making sure these are Photon feats and not PlayFab addon feats.

    -2-

    What do I do about billing when I'm ready to swap to GameSparks? I'm currently with PlayFab being Photon billed via them: Would I just swap the token with a PUN token directly through your site, then cancel through PlayFab?

    -3-

    Any future plans for GameSparks native support like there is with PlayFab? Mostly curious.

    Thanks again for your help!
  • Split this from your previous topic, as it is quite separate.

    -1-
    Yes, this is Photon related - see doc at https://doc.photonengine.com/en-us/realtime/current/reference/custom-authentication

    -2-
    What do you refer to with "PUN token"? The Photon appid?
    Switching a Playfab managed account to use GameSparks is not possible. To use GameSparks you would need to create a Photon account via our site and set up your Photon app (webhooks) to use GameSparks.

    -3-
    No current plans.
  • JohnTube
    JohnTube ✭✭✭✭✭
    Hi @xblade724,

    In case you or someone else is asking about how to do custom auth w/ GameSparks I started to try this myself.

    I managed to implement a basic username/password authentication.
    I want to find a way to make use of tokens instead.

    I can share more details if needed.
  • xblade724
    xblade724
    edited August 2017
    > I managed to implement a basic username/password authentication.

    Hey that's pretty cool of you to check it out! I'm also stuck at the token part, too. I asked GameSparks recently if there's a way to validate a token. I think there is -- I noticed in the JSON against your player, it stores your auth tokens[] as an array. We can probably search through it and see if the session matches.

    This is what I have so far, if it helps you and others:

    The callback looks like this:

    https://{{stage}}.gamesparks.net/callback/{{apiKey}}/photon/{{photonSecret}}/?gsid=1234&token=asdf&apiKey=zxcv&apiVer=1.0



    Then GS callback code:
    var SECRET = "nS------something-something:)";
    
    var myData = Spark.getData();
    
    var gsid = myData.gsid; // asdf123
    var myToken = myData.token; // "asdf-123"
    
    var apiKey = myData.apiKey; // from Photon, but also this credential secret "asdf-123"
    var apiVer = myData.apiVer; // "1.0"
    
    // Set fallbacks
    var resultCode = 3;
    var msg = "Unknown Error";
    var dName = "";
    
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Validate
    var err = false;
    if (!gsid)
    {
        err = true;
        msg = "Invalid user";
    }
    if (!myToken)
    {
        err = true;
        msg = "Invalid token";
    }
    if (!apiKey)
    {
        err = true;
        msg = "Invalid apiKey";
    }
    if (!apiVer)
    {
        err = true;
        msg = "Invalid apiVer";
    }
    if (err)
        returnData();
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
    // Get player and validate
    resultCode = 2;
    var p = Spark.loadPlayer(gsid);
    if (!p)
    {
        err = "Player Not Found";
        returnData();
    }
    
    // Validate authToken
    // TODO
    
    // Get the rest of the details
    resultCode = 1;
    dName = p.getDisplayName();
    msg = "Success";
    
    // Ready to send back, successfully!
    returnData();
    
    // ..........................................................
    function returnData()
    {
        // Set data to return
        Spark.setScriptData("ResultCode", resultCode);
        Spark.setScriptData("Message", msg);
        Spark.setScriptData("UserId", gsid);
        Spark.setScriptData("Nickname", dName);
        // Spark.setScriptData("AuthCookie", AuthCookie);
        // Spark.setScriptData("Data", {});   
        
        // Spark.setScriptData("RESPONSE_RAW", "Hello World!");
        Spark.exit();
    }
    // ====================================================
    // ResultCode Description UserId Nickname Data AuthCookie
    // 0 Authentication incomplete, only Data returned.* x x ? x
    // 1 Authentication successful. ? (optional) ? (optional) ? (optional) ? (optional)
    // 2 Authentication failed. Wrong credentials. x x x x
    // 3 Invalid parameters. x x x x
    // ====================================================

    Then Unity:
    // Set username via GS displayName
    PhotonNetwork.playerName = displayName;
    
    // Need some auth values (before we connect)
    AuthenticationValues customAuth = new AuthenticationValues();
    
    // Important: Select authentication type (how / where the auth is verified)
    customAuth.AuthType = CustomAuthenticationType.Custom;
    
    // The demo authentication-service expects values for "gsid" and "token"
    customAuth.AddAuthParameter("gsid", gsid);
    customAuth.AddAuthParameter("token", gsAuthToken);
    
    // Set UserId to find friends later (by gsid)
    customAuth.UserId = gsid;
    
    // Set the values
    PhotonNetwork.AuthValues = customAuth;
  • xblade724
    xblade724
    edited August 2017
    @JohnTube I think I got it. I wonder if we can access the "System" part of NOSQL. I see authTokens[] stored. Could iterate then verify.

    EDIT: I saw a ticket where someone was accessing it (via read-only). It's definitely possible. I submitted a ticket.
  • JohnTube
    JohnTube ✭✭✭✭✭
    hi @xblade724,

    let us know if you manage to get the token validation fully working.
    maybe share the ticket you are referring to.
    i'm thinking we could add one more custom auth repo to github :)
    thanks.
  • xblade724
    xblade724
    edited August 2017
    https://support.gamesparks.net/support/tickets/5888

    It seems that when you are authenticated, you can save "lastAuthTicket" or something wherever you save your custom player data in nosql. You'd then match the auth ticket like that.

    I'm on another project right now, but I'll swing back to this in a few days and show completed code. I'll probably save it at AuthenticationResponse -- pretty sure I can access auth there
  • xblade724
    xblade724
    edited October 2018
    @JohnTube sorry about the wait -- got distracted from finishing it since it was really difficult to test on multiple stages (meaning multiple callbacks/secrets). Here's my setup, assuming you have a "dev_preview -> live_preview (staging) -> live_live" setup recommended by GS tutorials.

    SETUP PHOTON (pre-req)
    Similar to GS, you should have 3 apps going. Your dev_preview branch (free will do - usually should be just you and a laptop), your live_preview (test realm - we bought that 100-person perpetual license that does well for this), and your main one you pay monthly for - all named appropriately.

    For preview mode (wait for live because you may block them out)
    1. Click "Manage".
    2. Uncheck "allow anon clients to connect": None of these are going to be anonymous
    3. Check "reject all clients if not available". They will be available.
    4. Create a GS callback: call it "photon". Player=OFF, listener=OFF, callback=ON, REST policy=forbidden, (optional) checkbox configure request types and set your own scopes. This callback should have very limited scopes since it only serves 1 purpose. Leave them all on for now and go back later when you know what calls you use.
    5. This makes a "photon" callback in GS cloud script. Open it up. Pause here on this tab.
    6. Jump back to Photon's manage section. EDIT the custom service provider. The authentication URL is as templated: https://{{gsApiKey}}.{{preview||live}}.gamesparks.net/callback/{{gsApiKey-again}}/photon/{{photonCredentialKey}} -- Note that these api keys are GAMESPARKS -- not photon keys.
    7. for keys/values section, make a value for your version in case you change it up later (like ver:1), and your key (key:makeUpSomeLongStrongKey). Google for a strong keyword generator. Note the key. When users auth, these kvp's will add to the end like a GET query: ?key=blah&ver=1
    8. Hop back to GS cloud code for photon callback.
    9. So, `var requestData = Spark.getData()` should contain your key, ver, and anything else you included within Unity's custom code. Go ahead and make a const for your secret (or pull from a meta db only server can access): Only continue if the secret matches.
    10. So now, we need to validate the GS token. Well, it's not here! Hop to Unity's custom auth. I'm going to already assume you know how to custom auth with Unity (that's a different tutorial). Let's add the playerId and authToken:
      ```
      // You should already be authenticated with GS and have these
      customAuth.AddAuthParameter("pid", pid);
      customAuth.AddAuthParameter("authToken", gsAuthToken);
      // And any other arbitrary data you wanna pass
      ```
    11. Now "pid" and "authToken" both show up in requestData. Now, GS doesn't let you search their System DB. So configure your setup so that at authentication response, you collect the token and save it in your own collection somewhere.
    12. Search the DB for the token and limit the scope result (projection) to your _id (assuming that's your pid). Check to see if the pid matching this token == the pid from requestData. Matches? Hurray! Authenticated. That's it, return success (return { "ResultCode" :1 }).
    13. Success will trigger your photon callbacks (....forgot which one, OnSuccesfulAuth or something) and bad ones will trigger a similar unauthed callback (apologies, from memory). I use a coroutine to watch for public bools to set @ the callbacks for success or fail to either continue or show a login screen error message.
    14. If the test works, detect what stage + apiKey you're on to change the secret keys between your other 2 modes. Don't forget, you may accidentally lock out your users if you don't get this 100% right. And you SHOULD have separate keys for different GS apiKeys. This is where it got confusing for me, personally. You have 3 different you need to handle differently: But only when it comes to the secret keys different for each callback.
    15. PRO TIP: Instead of writing your code at the callback, use a module so that you can test/step through from within GS's test harness. So your callback will have just one line of code requireOnce("PHOTON_MODULE_OR_SOMETHING"). Otherwise, you'd have to make a long GET url with tons of logs and keep refreshing as your only means of testing - sort of awkward.
    16. PRO TIP 2: The moment you verify matching secret keys, delete all traces of the secret so you don't accidentally include in the logs for some reason.
    This guide is horrible, I know -- but I'm hoping it's "enough" to actually figure it out or get some direction on how to do this. Hopefully someone will rewrite this guide into something better. I'm no word artist ;D

    Is it worth doing this? Probably not. It was a huge headache and took me forever to do it. BUT! We're trying to tighten up security, so it's worth it to **US**. Hopefully, Photon makes it easier for you folks one day that are like us, using both Photon+GS.