Using SAML SSO with Velo
The SAML Authentication Sequence
- The user clicks a sign-in button.
- The SP generates a SAML request using the IDP and SP metadata, and passes the request and URL to the browser.
- The browser sends the SAML request to the IDP.
- The IDP presents a login page, based on the SAML request.
- The user provides login credentials.
- The IDP posts the assertion to the SP. A SAML assertion is an XML document that contains the user authorization and user credentials.
- The SP decrypts, validates, and extracts the credentials from the assertion.
- The SP ( Wix backend) generates a session token, and passes a redirect back to the browser with the session token in the query parameters.
- The browser redirects to the front-end page.
- The session token is used to sign in automatically.

Setting Up
- Set the name of the callback function that handles the assertion
- Create an SSL certificate and private key pair.
- Set up the IDP.
- Download the IDP metadata.
- Set up the SP metadata.
Naming the Assertion Callback Function
Creating Certificates and Keys
openssl genrsa -out private.pem
openssl req -new -x509 -key private.pem -out public.crt
You will be asked a number of questions. It is enough to answer the first one with a two-letter country code.
This will producte two files, private.pem containing the private key and public.crt containing the public certificate. These files will be created in the directory where you ran the commands.
Remember where you put public.crt as we'll need it later.
Using the Secrets Manager
Setting Up the IDP
- Click Applications in the Auth0 dashboard.
- Click Create Application, give your application a name, select Regular Web Applications and click Create.
- Click Settings in the top bar.
- Scroll down to Allowed Callback URLs and enter the URL of your assertion function. This is the URL that the IDP will call with a POST when the user signs in. In our case that's going to be https://mysite.wixsite.com/saml-demo/_functions/assertion which corresponds to the function post_assertion in the http-functions.js file. More on that when we get to the code.
- Scroll to the bottom and click Save Changes.
- Scroll back up to the top bar and click Addons.
- Click SAML2 WEB APP.
- The IDP needs our public certificate and Auth0 requires that it fits on a single line.
The public key was that file we stored as public.crt earlier on.
In the settings box, add "signingCert": <public key> inside the curly braces.
The format for the public key is:
"-----BEGIN PUBLIC KEY-----nMIGf...bpP/t3\n+JGNGIRMj1hF1rnb6QIDAQAB\n-----END PUBLIC KEY-----\n"
so you will need to reformat your certificate to change all new-line characters (\n) to actual "\"s followed by "n"s
Use the following if you are on mac or linux:
$ awk '{printf "%s\\n", $0}' public.crt
Use the following command in PowerShell if you are on Windows:
PS C:\Users\Wix> (Get-Content .\public.crt) -join "\n"

1export const idpMetadata =`<EntityDescriptor entityID="urn:my-saml-test.us.auth0.com" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
2 <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
3 <KeyDescriptor use="signing">
4 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
5 <X509Data>
6 <X509Certificate>MIIDDTCCAfWgAwIBAgIJGBvK29ZE/GY1MA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGW15LXNhbWwtdGVzdC51cy5hdXRoMC5jb20wHhcNMjAxMDAxMDk0MjIyWhcNMzQwNjEwMDk0MjIyWjAkMSIwIAYDVQQDExlteS1zYW1sLXRlc3QudXMuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4yxmeg9zZn/Q1TzI27hQIknZaSklARUAlEtayykvrC9glB7SBuo1b0rz0w+M1GAKzdgcM3Ca0a0iC/wfH9a0YbXXE1vwj5tlMqISEKEPv/SOep1glPrK7m3s8ndPsfVN/4cxQbncVkLSgwORylWaU1UMU8Im3yvL7WcL0uSKCUQWr/XEbQsNqn+dDIjwXCAC2smXho7nm5Alz2xwR1bORLCLPTcJuy2pr0LxuzZiw366gADy/mG21OBOnPYqTbPZJuRE1I46av/atJVEPFrn3hklsyVaS4M3YEl7x+nW0rzenvqQvwh56ZDvF2cNUQBMqjtblclJd4ipp3x0bLuziQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQzlOf36gQB747obsUfV8wb6jLVAjAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAMs2wZW/CQtZFHS7tltolBNMDTuPokrRUlZYT6KoKdTh0Uk4Okq0luCEwAoxbyidpBMEWUIKP74iEttK72QiUF8Wf93DZtd0pC/IgMlFR+ef5z7IEunFTUJ0DsutdQh6BDPZKqoo/gG3eefBeCt0lYav/aF0v2+vzHZUc9wWGYuuKs8wjp4a+hxll3/lgzX/jGvvl69ckJ1TW71LtUF42RRtZcvbj5eC1xxC9jrF6hsLrdwQpaiVB0obyp260iXetc1cSuyVVThGQL3XIq4H7ngLGikJk53lESOJknn0DoTzg1mVnKZ6t47WcWU3eOQomgUVyxszkrwEpEmEXKEc+r8=</X509Certificate>
7 </X509Data>
8 </KeyInfo>
9 </KeyDescriptor>
10 <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://my-saml-test.us.auth0.com/samlp//1234567890yNX1W1MZQgfzwSmhG1YoN0/logout"/>
11 <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://my-saml-test.us.auth0.com/samlp/1234567890yNX1W1MZQgfzwSmhG1YoN0/logout"/>
12 <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
13 <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
14 <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
15 <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://my-saml-test.us.auth0.com/samlp/1234567890yNX1W1MZQgfzwSmhG1YoN0"/>
16 <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://my-saml-test.us.auth0.com/samlp//1234567890yNX1W1MZQgfzwSmhG1YoN0"/>
17 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="E-Mail Address" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
18 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Given Name" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
19 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Name" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
20 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Surname" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
21 <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Name ID" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
22 </IDPSSODescriptor>
23</EntityDescriptor>`
Setting up the SP Metadata
- Chose an EntitiyId, any unique name is OK. Let's use saml-demo.
- Attribute Consume Service Endpoint (HTTP-POST): This is where you enter the Assertion Consumer Service endpoint that will handle the assertion. In our case, as we defined above it's https://mysite.wixsite.com/saml-demo/_functions/assertion.
- SP X.509 cert: Open the public.crt file with a text editor. This is the file we created in the Certificates and Keys step. Copy and paste the file's content into the SP X.509 cert field.
- Set AuthnRequestsSigned and WantAssertionsSigned to True.
- Scroll down and hit BUILD SP METADATA.
- Copy the XML from the green SP Metatada box.
- In your WIx editor, open the backend file called metadata.js that you created for the IPD metadata and paste the copied XML into the file. Export it as spMetadata. Use back-ticks ( ` ) to enclose the XML so that the end of line is ignored.
Your code should look like this :
1 export const spMetadata = `<?xml version="1.0"?>
2<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2020-10-09T10:14:25Z" cacheDuration="PT604800S" entityID="saml-demo">
3 <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
4 <md:KeyDescriptor use="signing">
5 <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
6 <ds:X509Data>
7 <ds:X509Certificate>MIIE6DCCAtACCQCgAlaiRpc7ITANBgkqhkiG9w0BAQsFADA2MQswCQYDVQQGEwJJTDELMAkGA1UECAwCaWwxDTALBgNVBAcMBEhlcmUxCzAJBgNVBAoMAk1lMB4XDTIwMTAwNzA4NDc1N1oXDTIwMTEwNjA4NDc1N1owNjELMAkGA1UEBhMCSUwxCzAJBgNVBAgMAmlsMQ0wCwYDVQQHDARIZXJlMQswCQYDVQQKDAJNZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM1JcEsUkUWsQhqn5E61MEjzkyOJQoF91WrQTsKhNsA0KiRoVcZ4OkGUUFYWrSCZXxab3VrghBURhW9UhJE5zho9rXX1PHvqnzEtS+/hzoQgBFZG3Halo/U06HeVXD4n2uJTlb/K/1KHXbUsJ3IniIA+IRhmlP69Oi/ZVQvjkfLDBbillp4vMPcf/ReT0/IGG3zRPX61byLmVoWLxzuQlqhojilRgfdn+gvLpDgleMaw9FR0EjkolTj6VW6A7nlw5MTKaMDATUGRnfUP+pbnq4fluXdfVzcNHF3JFQ8ECvePm1XqAr9hwIk6UX50gFjUM1A+hSDt298V55iG6RugwLaoO83p5tVd3g0xkxamPRAKxxSZfNia3y4HJB8cGTVor4SnwvkL8mweIr/xmDayyFzLYl5Tux7uk/nwzFN80EG9MieEjFgTMKgXzi3TGnyJQspypM8dqyN6eUpn0N/rKB5jaeMgXnUqRhrKc0aQtMUkhqAzTMMWFnbDySAKHJhq+HI4SXFEXhf51GM2tkoEh8OBhwbcoB8tco60I7cBxT0kakqoFWHG5jCTd4ksGzUkXoTeYrQSyxE/DyCOfZBzkvljJLcqoOQwoukYV13WLOfsNgETIiAhe0PXhqi0B8kxn6SXVqhVaVKhsXiy4FbClLOefPFHH+wtViNYjWQUIVctAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAM0XAs4qZGwYN34YxqYThVHGDcWljO9DiKlCt3xbBBRX9ZI8VKOWHNtswdBbdraPtAMT0D052xSWMbXOGlnGWPHxjvLCsWfGDnxJ4KCyItkzKuoIm7LRmSpQWHDwZNTKlQVm9ap192vvOgLa53mHavOZJ7NPoVkO29MC7+NyUa8exn9Zj8XbRGr2pioYK4LMub4oFthuAHVg5RIzHmIMzJpZYew8OrSYXLHLDKLWNLQHDOwDl+Bic02IQIF/hCfflviGGLCk3yjiAVP4HnpkJgtdDkgMi+YihG8znlyHpSmB60WrlSjbbxgxkdmPePEhZP5BrYeSyV6ZM2I5dpj3GpG94JN5RC44BpL23IXlS89dzRfo/cKKIZ63uA45rH6vVNEqAnKfSFGRI0OuafEdx8Cirgkw7WXMHkzqEm5wYlt4XV5akavi0PErS9rrYGlMpfUxT2csyjCww6k/UaxBDaS9GAySAMwRPsuA853XY0/eSESWNj72i0bGCjT1Dx6MWaE/UVERTSL04qxK/ACJT9aMnOAjs2r1gFYZq57l1AC5eadXtcJt/s6C/uEXgvXhyPvvHnYisu7S2lu5rOg1N9cvVftWbeRgTgAEsr3cz04CZ4ZZRADhpVpE38Shq2vPNrf4qqkjbM1BgOGcXtx/lDVUUlM4l7FEjWNfrUWbueqh</ds:X509Certificate>
8 </ds:X509Data>
9 </ds:KeyInfo>
10 </md:KeyDescriptor>
11 <md:KeyDescriptor use="encryption">
12 <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
13 <ds:X509Data>
14 <ds:X509Certificate>MIIE6DCCAtACCQCgAlaiRpc7ITANBgkqhkiG9w0BAQsFADA2MQswCQYDVQQGEwJJTDELMAkGA1UECAwCaWwxDTALBgNVBAcMBEhlcmUxCzAJBgNVBAoMAk1lMB4XDTIwMTAwNzA4NDc1N1oXDTIwMTEwNjA4NDc1N1owNjELMAkGA1UEBhMCSUwxCzAJBgNVBAgMAmlsMQ0wCwYDVQQHDARIZXJlMQswCQYDVQQKDAJNZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM1JcEsUkUWsQhqn5E61MEjzkyOJQoF91WrQTsKhNsA0KiRoVcZ4OkGUUFYWrSCZXxab3VrghBURhW9UhJE5zho9rXX1PHvqnzEtS+/hzoQgBFZG3Halo/U06HeVXD4n2uJTlb/K/1KHXbUsJ3IniIA+IRhmlP69Oi/ZVQvjkfLDBbillp4vMPcf/ReT0/IGG3zRPX61byLmVoWLxzuQlqhojilRgfdn+gvLpDgleMaw9FR0EjkolTj6VW6A7nlw5MTKaMDATUGRnfUP+pbnq4fluXdfVzcNHF3JFQ8ECvePm1XqAr9hwIk6UX50gFjUM1A+hSDt298V55iG6RugwLaoO83p5tVd3g0xkxamPRAKxxSZfNia3y4HJB8cGTVor4SnwvkL8mweIr/xmDayyFzLYl5Tux7uk/nwzFN80EG9MieEjFgTMKgXzi3TGnyJQspypM8dqyN6eUpn0N/rKB5jaeMgXnUqRhrKc0aQtMUkhqAzTMMWFnbDySAKHJhq+HI4SXFEXhf51GM2tkoEh8OBhwbcoB8tco60I7cBxT0kakqoFWHG5jCTd4ksGzUkXoTeYrQSyxE/DyCOfZBzkvljJLcqoOQwoukYV13WLOfsNgETIiAhe0PXhqi0B8kxn6SXVqhVaVKhsXiy4FbClLOefPFHH+wtViNYjWQUIVctAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAM0XAs4qZGwYN34YxqYThVHGDcWljO9DiKlCt3xbBBRX9ZI8VKOWHNtswdBbdraPtAMT0D052xSWMbXOGlnGWPHxjvLCsWfGDnxJ4KCyItkzKuoIm7LRmSpQWHDwZNTKlQVm9ap192vvOgLa53mHavOZJ7NPoVkO29MC7+NyUa8exn9Zj8XbRGr2pioYK4LMub4oFthuAHVg5RIzHmIMzJpZYew8OrSYXLHLDKLWNLQHDOwDl+Bic02IQIF/hCfflviGGLCk3yjiAVP4HnpkJgtdDkgMi+YihG8znlyHpSmB60WrlSjbbxgxkdmPePEhZP5BrYeSyV6ZM2I5dpj3GpG94JN5RC44BpL23IXlS89dzRfo/cKKIZ63uA45rH6vVNEqAnKfSFGRI0OuafEdx8Cirgkw7WXMHkzqEm5wYlt4XV5akavi0PErS9rrYGlMpfUxT2csyjCww6k/UaxBDaS9GAySAMwRPsuA853XY0/eSESWNj72i0bGCjT1Dx6MWaE/UVERTSL04qxK/ACJT9aMnOAjs2r1gFYZq57l1AC5eadXtcJt/s6C/uEXgvXhyPvvHnYisu7S2lu5rOg1N9cvVftWbeRgTgAEsr3cz04CZ4ZZRADhpVpE38Shq2vPNrf4qqkjbM1BgOGcXtx/lDVUUlM4l7FEjWNfrUWbueqh</ds:X509Certificate>
15 </ds:X509Data>
16 </ds:KeyInfo>
17 </md:KeyDescriptor>
18 <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
19 <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://mysite.wixsite.com/saml-demo/_functions/assertion" index="1"/>
20 </md:SPSSODescriptor>
21</md:EntityDescriptor>`
- SPSSODescriptor Line 3. Make sure that AuthnRequestsSigned="true" WantAssertionsSigned="true" are both there. If not, or if they are false, it may cause trouble later on when creating the ServiceProvider and IdentityProvider objects.
- AssertionConsumerService Binding, Line 19. This holds the URL that will handle the callback once our visitor has signed in. i.e. "https://mysite.wixsite.com/saml-demo/_functions/assertion"
Installing the Samlify Package
- Click on the CODE FILES button on the left sidebar of the editor.
- In Packages (npm), click Install a New Package.
- Search for "samlify" and click Install next to the samlify package

Adding the Code
- saml.jsw: Accessible from the front end, to generate SAML requests.
- create-providers.js: To work with the samlify package to create the SP and IDP objects. This is a .js file and therefore not accessible from the front end. We do not want these functions accessible from the front end as they contain metadata and secrets that we do not want to expose.
- http-functions.js: To handle the assertion callback from the IDP, and retrieve the user's details.
Adding Landing Page Code
1import wixLocation from 'wix-location';
2import {session} from 'wix-storage';
3import { generateSAMLRequest } from 'backend/saml.jsw';
4
5$w.onReady(function () {
6
7 $w('#loginButton').onClick(() => {
8 generateSAMLRequest()
9 .then((request) => {
10 session.setItem("requestId", request.id);
11 wixLocation.to(request.context);
12 });
13 });
14});
Understanding the Code
Lines 1-2: Import the modules that we will work with, incuding our backend function, generateSAMLRequest
, which we will create below.
Lines 7-8: When a site visitor clicks login the button, we call the backend generateSAMLRequest
function, which will return the SAML request Id, and the URL with the SAML request.
Line 10: Store the requestId
in the session variables. The requestId
will be compared to the inResponseTo
Id that is returend in the SAML response. This will help us protect against someone copying the final log-in URL and the session token.
Line 11: Direct the browser to the request URL with wixLocation.to
, so the visitor can log in using their credentials on the IDP.
Generating the SAML Request
1import { notFound } from 'wix-http-functions';
2import {createIdp, createSp} from 'backend/create-providers';
3
4export async function generateSAMLRequest() {
5 try {
6 //create the idp and sp objects using samlify
7 const idp = await createIdp();
8 const sp = await createSp();
9
10 //create the request url and return it and the request id to the fronted page.
11 const { id, context } = sp.createLoginRequest(idp, 'redirect')
12 return {id,context};
13
14 } catch (error) {
15 console.error('generateSAMLRequest error:', error.message);
16 return notFound({ status: 404 });
17 }
18}
Understanding the Code
Lines 1-2: Import the modules that we will work with.
Lines 7-8: When the front end calls generateSAMLRequest
, we create the identity provider and service provider objects using createIdp
and createSp
.
Lines 11-12: Use the samlify function, createLoginRequest
to generate the SAML request id and URL and return them to the front end. The request id will be matched with the inResponseTo
id in the SAML response.
1import { getSecret } from 'wix-secrets-backend';
2import { IdentityProvider, ServiceProvider } from 'samlify';
3import { spMetadata, idpMetadata } from 'backend/metadata.js';
4
5export function createIdp() {
6 //create the IdentityProvider object using the metadata in idpMetadata
7 try {
8 const idp = IdentityProvider({
9 metadata: idpMetadata
10 });
11 return idp;
12 } catch (error) {
13 console.error('Error in createIdp detected', error.message);
14 }
15}
Understanding the Code
Lines 1-3: Import the modules that we will work with. Note the import of spMetadata
and idpMetadata
from backend/metadata.js
. We created the metadata.js
file when setting up the IDP and setting up the SP metadata.
Line 8: Use the samlify IdentityProider
object and the metadata from the identity provider to create the idp
object.
This object is used when creating the login request and again when we parse the login response in the http-functions
.
Line 11: Return the idp
object to the generateSAMLRequest
function
1export async function createSp() {
2 try {
3
4 // retrieve the private key from the Secrets Manager
5 const spPrivateKey = await getSecret('spPrivateKey');
6
7 //create the ServiceProvider object usning the metadata and the private key
8 const sp = ServiceProvider({
9 metadata: spMetadata,
10 privateKey: spPrivateKey
11 });
12 return sp;
13
14 } catch (error) {
15 console.error('Error in createSp detected', error.message);
16 }
17}
Understanding the Code
Line 5: Retrieve the private key that was stored in the Secrets Manager in the Using the Secrets Manager section.
Lines 8-10: Use the samlify ServiceProider
object, metadata for the service provider, and the private key, to create the sp
object.
Line 12: Return the sp
object to the generateSAMLRequest
function.
ERR_METADATA_CONFLICT_REQUEST_SIGNED_FLAG,
and is caused by not setting WantAuthnRequestsSigned="true" in the IDP metadata when the SP metadata has AuthnRequestsSigned="true" in the SPSSODescriptor, or having AuthnRequestsSigned="false".Handling the AssertionConsumerService Request
1import { response, ok, notFound } from 'wix-http-functions';
2import { createIdp, createSp } from 'backend/create-providers.js';
3import * as samlify from 'samlify';
4import { authentication } from 'wix-members-backend';
5
6const baseUrl = 'https://mysite.wixsite.com/saml-demo';
7
8export async function post_assertion(request) {
9 try {
10 const [idp, sp] = await Promise.all([createIdp(), createSp()]);
11
12 // we are not using the validation in our example, but if we dont call it, we'll get an error.
13 samlify.setSchemaValidator({
14 validate() {
15 return Promise.resolve('skipped');
16 }
17 });
18
19 const requestBody = await request.body.text();
20 const samlResponse = {
21 body: {
22 SAMLResponse: decodeURIComponent(requestBody.split('SAMLResponse=')[1])
23 }
24 }
25
26 // parse and decrypt the response
27 const parseResult = await sp.parseLoginResponse(idp, 'post', samlResponse);
28
29 //extract the inResponseTo Id
30 const inResponseTo=parseResult.extract.response.inResponseTo
31
32 //extract the email address
33 const email = parseResult.extract.attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'];
34
35 //create the session token to use when logging the visitor in
36 const sessionToken = await authentication.generateSessionToken(email);
37
38 return response({
39 status: 302,
40 headers: {
41 'Location': `${baseUrl}/signed-in?session=${sessionToken}&response=${inResponseTo}`
42 }
43 });
44
45 } catch (error) {
46 const body = await request.body.text();
47 console.error('Error in post_asc', error.message);
48 return notFound({ status: 404 });
49 }
50}
Understanding the Code
Line 6: Set the base URL for the site. Change this to suite your site.
Line 8: Create the assertion
function to handle the post
request from the IDP.
Line10: Create the idp
and sp
objects using the createIdp
and createSp
imported from saml.jsw
.
Lines13-15: Samlify requires that the response is validated, but we are not going to deal with that in this tutorial. For more details see how to set up a validator. Call setSchemaValidator and return a resolved promise.
Line 19: Get the http request body in text format.
Line20: The response body may differ between IDPs. Take the data that comes after SAMLResponse=
using the split function and decode it. Reconstruct the response object, adding the body
so it can be parsed.
Line 27: Use the samlify function parseLoginResponse
to decrypt and extract the XML that is our readable SAML response.
Line 30: Extract the inResponseTo
Id which will be matched to the request Id when the user is signed in.
Line 33: Extract the email address from the SAML response XML. Note that the attribute name for the email address will differ for each IDP.
Line 36: Use the email address to create a Wix session token using the wix-members-backend function, generateSessionToken. This token will allow us to log the visitor in to our Wix site. If the email address corresponds to an existing member, a session token for that member is generated. If no member exists with that email address, a new member is created along with a session token for logging that member in.
Lines 38-41: Return a redirect URL, directing the browser to the signed-in landing page, adding the session token and inResponseTo
Id as query fields.
Signed-in Landing Page
1import wixLocation from 'wix-location';
2import { session } from 'wix-storage';
3import { authentication } from 'wix-members';
4
5$w.onReady(() => {
6
7 const query = wixLocation.query;
8 const sessionToken = query.session;
9 const responseID = query.response;
10 const requestID = session.getItem("requestId")
11
12 if (sessionToken && (responseID === requestID)) {
13 authentication.applySessionToken(sessionToken)
14 } else {
15 console.error("Signin Failed", sessionToken)
16 wixLocation.to('https://mysite.wixsite.com/saml-demo')
17 }
18});
Understanding the Code
Lines 7-9: Retrieve the session token and inResponseTo
id from the query parameters.
Line 10: Retrieve the requestId
that was stored in the session variables before signing in.
Lines 12-13: If the requestId
matches the inResponseTo
Id, then we know that this broswe session is the one that made the login request. If a session token exists, apply the session token to log the visitor in.
Lines 15-16: If there is no session token, or the Ids do not match, return the visitor to the log-in page. Change the URL on line 16 to suite your site.