No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
====== Intro and | ====== Intro and Explanations ====== | ||
In order to connect SPA's built with pure-javascript or React or Angular or Vue or anthing else we must address these needs: | In order to connect SPA's built with pure-javascript or React or Angular or Vue or anthing else, we must address these needs: | ||
# Cors - | # Cors - allows foreign apps to query our Turnkey server - [[Cors|read specifics here.]] | ||
# Authentication - | # Authentication - allows foreign apps to acquire a jwt from somewhere (Oauth host) - and we want to check it and possibly accept it. | ||
# Stay logged in - with a cookie after initial authentication | # 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 | 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 | If you follow all the instructions there, you soon have an 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: | Once you have this example - follow the lead and add another button, just like the readMail and seeProfile buttons from the sample: | ||
Line 38: | Line 38: | ||
}); | }); | ||
} | } | ||
</pre>What we do here is to acquire a new idToken, and | </pre>What we do here is to acquire a new idToken, and send 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: | The json we get from this call is sent to updateUI where we do this: | ||
Line 51: | Line 51: | ||
} | } | ||
}</pre>To handle | }</pre>To handle Cors and Authentication in the model, I follow the stipulated pattern and add this: | ||
[[File:2021-02-28 23h24 21.png|none|thumb|780x780px]] | [[File:2021-02-28 23h24 21.png|none|thumb|780x780px]] | ||
Line 72: | Line 72: | ||
==== Checklist ==== | ==== Checklist ==== | ||
Make sure your Azure app registration says SPA and not only Web | 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. | 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 | 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) | 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) | ||
Line 82: | Line 82: | ||
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 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 | 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 | ====== 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|SPA website 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|SPA website example.]] | ||
The Turnkey system that the demo SPA app gets data from can be downloaded here: [[Special:Redirect/file/MDrivenTurnkeyThatServeTheSPA.zip|Turnkey model that servers the SPA]] | The Turnkey system that the demo SPA app gets data from can be downloaded here: [[Special:Redirect/file/MDrivenTurnkeyThatServeTheSPA.zip|Turnkey model that servers the SPA]] | ||
# Start | # Start Visual Studio and open the SPA website as "website" - run it - navigate to yourlocaladress/app3 to see the UI | ||
# In order | # In order to login, you need to create an App registration on any Azure account - and make a note of particulars and update the website code so it matches what you got: [[File:2021-03-01 09h27 59.png|none|thumb]] | ||
Now your SPA app should be able to 1. start, 2. Login with | Now your SPA app should be able to 1. start, 2. Login with an account in your azureAD or any azureAD depending on your settings in the app registration: | ||
[[File:2021-03-01 09h33 17.png|none|thumb]] | [[File:2021-03-01 09h33 17.png|none|thumb]] | ||
This is how it should look once logged in: | This is how it should look once logged in: | ||
Line 96: | Line 96: | ||
Read Turnkey button must have a functioning Turnkey server in order to work. Start MDrivenDesigner and open the downloaded Modlr file. | Read Turnkey button must have a functioning Turnkey server in order to work. Start MDrivenDesigner and open the downloaded Modlr file. | ||
[[File:2021-03-01 09h38 43.png|none|thumb|600x600px]] | [[File:2021-03-01 09h38 43.png|none|thumb|600x600px]] | ||
If | If your server has another address than localhost:5052 - change the SPA app accordingly: | ||
[[File:2021-03-01 09h40 43.png|none|thumb|502x502px]] | [[File:2021-03-01 09h40 43.png|none|thumb|502x502px]] | ||
The modlr file also had data in the xml persistence - that defines keys and KnownApp-objects | The modlr file also had data in the xml persistence - that defines keys and KnownApp-objects. If your URLs are different, you may need to update in the knownApp object: | ||
[[File:2021-03-01 09h45 35.png|none|thumb|428x428px]] | [[File:2021-03-01 09h45 35.png|none|thumb|428x428px]] | ||
[[File:2021-03-01 09h42 53.png|none|thumb|445x445px]]Register an account on the Turnkey-app with the same email address as the account you use in your SPA app - and log in, you can now see the RestApi result here: http://localhost:5052/Turnkey/AngularApp#/RestExample/$null$ | [[File:2021-03-01 09h42 53.png|none|thumb|445x445px]]Register an account on the Turnkey-app with the same email address as the account you use in your SPA app - and log in, you can now see the RestApi result here: http://localhost:5052/Turnkey/AngularApp#/RestExample/$null$ | ||
Line 104: | Line 104: | ||
We can now test that we get the same result when running the SPA app rest call: | We can now test that we get the same result when running the SPA app rest call: | ||
[[File:2021-03-01 09h53 07.png|none|thumb|782x782px]] | [[File:2021-03-01 09h53 07.png|none|thumb|782x782px]] | ||
You can also verify that | You can also verify that you do not get any data if the account-email does not match, or if you are not logged in. | ||
[[Category:MDriven Turnkey]] | [[Category:MDriven Turnkey]] |
Revision as of 07:46, 28 March 2023
Intro and Explanations
In order to connect SPA's built with pure-javascript or React or Angular or Vue or anthing else, we must address these needs:
- Cors - allows foreign apps to query our Turnkey server - read specifics here.
- Authentication - allows foreign apps to acquire a jwt from somewhere (Oauth host) - and we want to check it and possibly accept it.
- 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 an 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 send 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:
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: Turnkey model that servers the SPA
- Start Visual Studio and open the SPA website as "website" - run it - navigate to yourlocaladress/app3 to see the UI
- In order to login, you need to create an App registration on any Azure account - and make a note of particulars and update the website code so it matches what you got:
Now your SPA app should be able to 1. start, 2. Login with an account in your azureAD or any azureAD depending on your settings in the app registration:
This is how it should look once logged in:
Read Turnkey button must have a functioning Turnkey server in order to work. Start MDrivenDesigner and open the downloaded Modlr file.
If your server has another address than localhost:5052 - change the SPA app accordingly:
The modlr file also had data in the xml persistence - that defines keys and KnownApp-objects. If your URLs are different, you may need to update in the knownApp object:
Register an account on the Turnkey-app with the same email address as the account you use in your SPA app - and log in, you can now see the RestApi result here: http://localhost:5052/Turnkey/AngularApp#/RestExample/$null$
We can now test that we get the same result when running the SPA app rest call:
You can also verify that you do not get any data if the account-email does not match, or if you are not logged in.