Connecting javascript SinglePageApplications to Turnkey (SPA)
Line 84: Line 84:


====== Code example ======
====== Code example ======
The demo SPA app is taken from  https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code with a few small additions and config-changes. You can download these changes from here instead: [[Special:Redirect/file/Ms-identity-javascript-v2.zip]]
The demo SPA app is taken from  https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code with a few small additions and config-changes. You can download these changes from here instead: [[Special:Redirect/file/Ms-identity-javascript-v2.zip|SPA website example]]


The Turnkey system that the demo SPA app gets data from can be downloaded here:
The Turnkey system that the demo SPA app gets data from can be downloaded here:

Revision as of 08:22, 1 March 2021

In order to connect SPA's built with pure-javascript or React or Angular or Vue or anthing else we must address these needs:

  1. Cors - allow foreign apps to query our Turnkey server - read specifics here
  2. Authentication - allow foreign apps to acquire a jwt from somewhere (Oauth host) and we want to check it and possibly accept it
  3. Stay logged in - with a cookie after initial authentication

To show this we can use the Microsoft SPA example from here : https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code

If you follow all the instructions there you soon have a SPA application that logs in with Azure AD - and gives you idToken that are in jwt format (really jws as they are signed).

Once you have this example - follow the lead and add another button, just like the readMail and seeProfile buttons from the sample:

function readTurnkey() {
    getTokenPopup(loginRequest)
        .then(response => {

            const headers = new Headers();
            const bearer = `Bearer ${response.idToken}`;
            const endpoint ='http://localhost:5052/TurnkeyRest/Get?command=RestExample'
            headers.append("Authorization", bearer);

            const options = {
                method: "GET",
                headers: headers
            };

            console.log('request made to Turnkey API at: ' + new Date().toString());

            fetch(endpoint, options)
                .then(response => response.json())
                .then(response => updateUI(response, endpoint))
                .catch(error => { console.log(error); });



        }).catch(error => {
            console.error(error);
        });
}

What we do here is to acquire a new idToken, and sending it to a Turnkey Rest api that in this case is at http://localhost:5052/TurnkeyRest/Get?command=RestExample

The json we get from this call is sent to updateUI where we do this:

   else {
        // turnkey data:
        try {
            profileDiv.innerHTML = JSON.stringify(data);
        }
        catch (err) {
            profileDiv.innerHTML = data.toString();
        }

    }

To handle cors and Authentication in the model I follow the stipulated pattern and add this:

2021-02-28 23h24 21.png

The methods are implemented like this:

GetAllowOriging:

if KnownExternalApp.allinstances->exists(x|(x.Origin=org) and (x.IsOk)) then  
  true -- we want to allow this app to call us 
else  
  false 
endif 

AcceptAndTransformUserName: 
if KnownExternalApp.allinstances->exists(x|(x.Audience=audience) and (x.IsOk)) then  
  user -- we want to allow all users from this domain if they exists in our domain 
else  
  '' 
endif

Checklist

Make sure your Azure app registration says SPA and not only Web

Make sure your Modulus attribute is made longer than 255 chars -> say 500 chars to be sure.

The Audience property is equal to your Application identity; a guid you get from azure (or google or your auth provider)

Find the ouath provider keys from the oauth-server, you find Azure here: https://login.microsoftonline.com/common/discovery/v2.0/keys (there will be multiple - 5ish)

Create a SysExternalJWTDefinition for each unique "kid"== key-identifier, and copy the "n" value to Modulus attribute(Make it 500 chars long so all of it fits!), copy the "e" to the exponent attribute.

Create a KnownExternalApp and set its origin to the url its hosted on (add many objects if its hosted on many servers), in my example: for http://localhost:62031 paste in the Application idenity from your oauth provider in the Audience attribute, set IsOk to true.

Code example

The demo SPA app is taken from https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code with a few small additions and config-changes. You can download these changes from here instead: SPA website example

The Turnkey system that the demo SPA app gets data from can be downloaded here:

This page was edited 98 days ago on 02/10/2024. What links here