Work with Okta (Credit to @fas3r)
?> In this chapter, we will make an sample application that implements SP-initiated SSO.
Pre-requirement:
samlify, express (or other), body-parser.
Step-by-step tutorial:
- Create a new web app with SAML2.0 in okta :

- Configure SAML_integration:
General setting:

Configure SAML :
!> Never upload your private key online

- "Single Sign on URL": the uri where to "POST" the auth request
- "Audience URI": The uri where the metadata are accessible. This is not mandatory if you don't want to share the metadata file. See here
- "Assertion Encryption": We set to "Encrypted". Indicates whether the SAML assertion is encrypted.
- "Encryption Certificate" : Upload the path to the certificate
*.certo use to encrypt the assertion.

- and the attributes statement/groups to return in the assertion section
Feedback:

* Choose your desired one.
- Next you will see in the "Sign On" tab the following :

- Red Arrow: The SAML 2.0 Certificate
- Green Arrow: Get the idp XML file of your application with all the information
- Blue Arrow: Direct link to the metadata file of the application.
- In the "General" tab you should see something like :

- Example code snippet
js
const express = require('express');
const fs = require('fs');
const saml = require('samlify');
const axios = require('axios');
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(serveStatic(path.resolve(__dirname, 'public')));
// URL to the okta metadata
const uri_okta_metadata = 'https://dev-xxxxxxx.oktapreview.com/app/APP_ID/sso/saml/metadata';
axios.get(uri_okta_metadata)
.then(response => {
const idp = saml.IdentityProvider({
metadata: response.data,
isAssertionEncrypted: true,
messageSigningOrder: 'encrypt-then-sign',
wantLogoutRequestSigned: true
});
const sp = saml.ServiceProvider({
entityID: 'http://localhost:8080/sp/metadata?encrypted=true',
authnRequestsSigned: false,
wantAssertionsSigned: true,
wantMessageSigned: true,
wantLogoutResponseSigned: true,
wantLogoutRequestSigned: true,
// the private key (.pem) use to sign the assertion;
privateKey: fs.readFileSync(__dirname + '/ssl/sign/privkey.pem'),
// the private key pass;
privateKeyPass: 'VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px',
// the private key (.pem) use to encrypt the assertion;
encPrivateKey: fs.readFileSync(__dirname + '/ssl/encrypt/privkey.pem'),
isAssertionEncrypted: true,
assertionConsumerService: [{
Binding: saml.Constants.namespace.binding.post,
Location: 'http://localhost:8080/sp/acs?encrypted=true',
}]
});
app.post('/sp/acs', async (req, res) => {
try {
const { extract } = await sp.parseLoginResponse(idp, 'post', req);
console.log(extract.attributes);
/**
*
* Implement your logic here.
* extract.attributes, should contains : firstName, lastName, email, uid, groups
*
**/
} catch (e) {
console.error('[FATAL] when parsing login response sent from okta', e);
return res.redirect('/');
}
});
app.get('/login', async (req, res) => {
const { id, context } = await sp.createLoginRequest(idp, 'redirect');
console.log(context);
return res.redirect(context);
});
app.get('/sp/metadata', (req, res) => {
console.log("here");
res.header('Content-Type', 'text/xml').send(idp.getMetadata());
});
});