<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicholas Irving</title>
    <description>The latest articles on DEV Community by Nicholas Irving (@nicholas_irving_293cdc88e).</description>
    <link>https://dev.to/nicholas_irving_293cdc88e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1597021%2F21cfec8f-ea4a-4649-a852-c24c66ef1af6.jpg</url>
      <title>DEV Community: Nicholas Irving</title>
      <link>https://dev.to/nicholas_irving_293cdc88e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicholas_irving_293cdc88e"/>
    <language>en</language>
    <item>
      <title>How to emulate CIBA with ForgeRock Access Manager</title>
      <dc:creator>Nicholas Irving</dc:creator>
      <pubDate>Mon, 15 Jul 2024 23:32:03 +0000</pubDate>
      <link>https://dev.to/nicholas_irving_293cdc88e/how-to-emulate-ciba-with-forgerock-access-manager-50id</link>
      <guid>https://dev.to/nicholas_irving_293cdc88e/how-to-emulate-ciba-with-forgerock-access-manager-50id</guid>
      <description>&lt;p&gt;We had a need to create a Customer Service Representative Demo to showcase how to use ForgeRock Access Manager aka PingAM, and we followed the guide at &lt;a href="https://backstage.forgerock.com/docs/idcloud/latest/am-oidc1/openid-connect-backchannel-request-flow.html" rel="noopener noreferrer"&gt;https://backstage.forgerock.com/docs/idcloud/latest/am-oidc1/openid-connect-backchannel-request-flow.html&lt;/a&gt; to configure our instance. However our problem is that we dont have access to configure the Push Notification Service, so what we decided to do was mock those interfaces using &lt;code&gt;Scripted Decision Nodes&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Here are the steps&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Scripted Decision Nodes with &lt;code&gt;Next Generation&lt;/code&gt; - &lt;code&gt;JavaScript&lt;/code&gt;.
&lt;/h2&gt;

&lt;p&gt;We created 2 Scripts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CIBA-PushSender&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  logger.warn("CIBA-PushSender: {}", "Sent");
  action.goTo("Sent");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CIBA-PushResultVerifierNode&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   logger.warn("CIBA-PushResultVerifierNode: {}", "Success");
   action.goTo("Success");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Created a cibaInit Journey
&lt;/h2&gt;

&lt;p&gt;A journey named &lt;code&gt;cibaInit&lt;/code&gt; was created that replicated the example provided by ForgeRock, but using &lt;code&gt;Scripted Decision Nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkby00lksiuga4z0l7wla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkby00lksiuga4z0l7wla.png" alt="Image description" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Username Collector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzfztsl5c0thxrkbehuc.png" alt="Image description" width="307" height="187"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Push Sender&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhio60kqlgmyypt14bbf.png" alt="Image description" width="298" height="643"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Pushed Result Verifier Node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8kjxn09mj9p2302fh6w.png" alt="Image description" width="300" height="634"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Polling Wait Node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkxpei90wsbirujqzzfy.png" alt="Image description" width="311" height="635"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Created a BackChannel Application
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://mkjwk.org/" rel="noopener noreferrer"&gt;https://mkjwk.org/&lt;/a&gt; we used the following config&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66i9efyplyzmrztehomc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66i9efyplyzmrztehomc.png" alt="Image description" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was then used to configure an &lt;code&gt;Application&lt;/code&gt; called &lt;code&gt;BackChannel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0iiafaw78zssfah79l8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0iiafaw78zssfah79l8j.png" alt="Image description" width="800" height="1394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Now we have all the basics in place we start testing the solution. In essence everything in the &lt;code&gt;cibaInit&lt;/code&gt; journey will just passthrough to get the Access Token, so there should be no delays or issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request a &lt;code&gt;auth-req-id&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This requires a JWt Signed by the keys supplied to FRAM. &lt;br&gt;
In Postman we use the following &lt;code&gt;Pre-request&lt;/code&gt; script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var jwtPrivateKey = `-----BEGIN PRIVATE KEY-----
....
-----END PRIVATE KEY-----`;

// Set headers for JWT
var header = {
    'alg': 'ES256',
    'typ': 'JWT',
    'kid': 'myCibaKey'
};

// Prepare timestamp in seconds
var currentTimestamp = Math.floor(Date.now() / 1000);


var payload = {
  "aud": "https://xxxx.xxxx.darkedges.com/openam/oauth2",
  "binding_message": "Allow ExampleBank to transfer £50 from 'Main' to 'Savings'? (EB-0246326)",
  "acr_values": "email",
  "exp":  currentTimestamp + 60 * 5,
  "iss": "BackChannel",
  "login_hint": "&amp;lt;email address of user&amp;gt;",
  "scope": "openid profile"
};

function generateJwt() {
    eval(pm.globals.get('jsrsasign-js')); // import javascript jsrsasign

    var sHeader = JSON.stringify(header);
    var sPayload = JSON.stringify(payload);

    var signedToken = KJUR.jws.JWS.sign(header.alg, sHeader, sPayload, jwtPrivateKey);

    pm.environment.set('signed-jwt', signedToken);
    console.log('jwt', signedToken);
}

var navigator = {}; // fake a navigator object for the lib
var window = {}; // fake a window object for the lib

if (pm.globals.has('jsrsasign-js')) generateJwt();
else pm.sendRequest(
    'https://kjur.github.io/jsrsasign/jsrsasign-all-min.js',
    function (err, res) {
        if (err) {
            console.log(err);
        } else {
            pm.globals.set('jsrsasign-js', res.text());
            generateJwt();
        }});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it creates the following request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location curl --location 'https://xxxx.xxxx.darkedges.com/openam/oauth2/bc-authorize' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: ••••••' \
--data-urlencode 'request=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im15Q2liYUtleSJ9.eyJhdWQiOiJodHRwczovL3h4eHgueHh4eC5kYXJrZWRnZXMuY29tL29wZW5hbS9vYXV0aDIiLCJiaW5kaW5nX21lc3NhZ2UiOiJBbGxvdyBFeGFtcGxlQmFuayB0byB0cmFuc2ZlciDCozUwIGZyb20gJ01haW4nIHRvICdTYXZpbmdzJz8gKEVCLTAyNDYzMjYpIiwiYWNyX3ZhbHVlcyI6ImVtYWlsIiwiZXhwIjoxNzIxMDg1ODQ2LCJpc3MiOiJCYWNrQ2hhbm5lbCIsImxvZ2luX2hpbnQiOiI8ZW1haWwgYWRkcmVzcyBvZiB1c2VyPiIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUifQ.BA-FkcK4c6J8Heh7dxT6RJLmW6HTe4FZ7b2KSRcFiOFQhp18y_9Taquj0LRNcDBz8w_1qHejvfEAWCEtv8ZosQ'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "auth_req_id": "TNrRNWXB86jFthHehaBfyinMpYI",
    "expires_in": 600,
    "interval": 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get Access Token
&lt;/h3&gt;

&lt;p&gt;Now we can get the Access Token for the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location 'https://xxxx.xxxx.darkedges.com/openam/oauth2/access_token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: ••••••' \
--data-urlencode 'auth_req_id=TNrRNWXB86jFthHehaBfyinMpYI' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIodXNyITxlbWFpbCBhZGRyZXNzIG9mIHVzZXI-KSIsImN0cyI6Ik9BVVRIMl9TVEFURUxFU1NfR1JBTlQiLCJhdWRpdFRyYWNraW5nSWQiOiJjMGZlNzcwMi02NTE1LTRhMjgtYjFkNi1kNjMxZTRhYjcxNjAtMTM5MjIiLCJzdWJuYW1lIjoiPGVtYWlsIGFkZHJlc3Mgb2YgdXNlcj4iLCJpc3MiOiJodHRwczovL3h4eHgueHh4eC5kYXJrZWRnZXMuY29tL29wZW5hbS9vYXV0aDIiLCJ0b2tlbk5hbWUiOiJhY2Nlc3NfdG9rZW4iLCJ0b2tlbl90eXBlIjoiQmVhcmVyIiwiYXV0aEdyYW50SWQiOiJzVWZHUE1ZMUpjV3J6NVVsWVhHTnhnTGs5c28iLCJhdWQiOiJCYWNrQ2hhbm5lbCIsIm5iZiI6MTcyMTA4NTYzOCwiZ3JhbnRfdHlwZSI6InVybjpvcGVuaWQ6cGFyYW1zOmdyYW50LXR5cGU6Y2liYSIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiXSwiYXV0aF90aW1lIjoxNzIxMDg1NjM4LCJyZWFsbSI6Ii9jb25uZWN0aWQiLCJleHAiOjE3MjEwODkyMzgsImlhdCI6MTcyMTA4NTYzOCwiZXhwaXJlc19pbiI6MzYwMCwianRpIjoiQ1dPTXh5UEpxUzdFR2huNWxzemJjYWF1SlVrIn0.eVG8sBmJY6BvROzDTOjKfGTXzK8SdcYMWbLanrLCgUk",
    "scope": "openid profile",
    "id_token": "eyJ0eXAiOiJKV1QiLCJraWQiOiI4dEZoOURsSnI4SU56OTl6VjBCU094UkdieE09IiwiYWxnIjoiSFMyNTYifQ.eyJhdF9oYXNoIjoiMkJWeDJYZ2Y1UmZJdlhnaEpWVlVpQSIsInN1YiI6Iih1c3IhPGVtYWlsIGFkZHJlc3Mgb2YgdXNlcj4pIiwiYXVkaXRUcmFja2luZ0lkIjoiYzBmZTc3MDItNjUxNS00YTI4LWIxZDYtZDYzMWU0YWI3MTYwLTEzOTIzIiwic3VibmFtZSI6IjxlbWFpbCBhZGRyZXNzIG9mIHVzZXI-IiwiaXNzIjoiaHR0cHM6Ly94eHh4Lnh4eHguZGFya2VkZ2VzLmNvbS9vcGVuYW0vb2F1dCIsInRva2VuTmFtZSI6ImlkX3Rva2VuIiwiZ2l2ZW5fbmFtZSI6IkRlbW8iLCJhdWQiOiJCYWNrQ2hhbm5lbCIsImF6cCI6IkJhY2tDaGFubmVsIiwiYXV0aF90aW1lIjoxNzIxMDg1NjM4LCJuYW1lIjoiRGVtbyBVc2VyIiwicmVhbG0iOiIvY29ubmVjdGlkIiwiZXhwIjoxNzIxMDg5MjM4LCJ0b2tlblR5cGUiOiJKV1RUb2tlbiIsImlhdCI6MTcyMTA4NTYzOCwiZmFtaWx5X25hbWUiOiJVc2VyIn0.7YxVoJ7s-enmQrbNduOQ5Aq57LAi5XVeHApvlzAOJnU",
    "token_type": "Bearer",
    "expires_in": 3599
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Introspect the Access Token
&lt;/h3&gt;

&lt;p&gt;We can now finally introspect the Access Token&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location 'https://fram.connectid.darkedges.com/openam/oauth2/introspect' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: ••••••' \
--data-urlencode 'token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIodXNyITxlbWFpbCBhZGRyZXNzIG9mIHVzZXI-KSIsImN0cyI6Ik9BVVRIMl9TVEFURUxFU1NfR1JBTlQiLCJhdWRpdFRyYWNraW5nSWQiOiJjMGZlNzcwMi02NTE1LTRhMjgtYjFkNi1kNjMxZTRhYjcxNjAtMTM5MjIiLCJzdWJuYW1lIjoiPGVtYWlsIGFkZHJlc3Mgb2YgdXNlcj4iLCJpc3MiOiJodHRwczovL3h4eHgueHh4eC5kYXJrZWRnZXMuY29tL29wZW5hbS9vYXV0aDIiLCJ0b2tlbk5hbWUiOiJhY2Nlc3NfdG9rZW4iLCJ0b2tlbl90eXBlIjoiQmVhcmVyIiwiYXV0aEdyYW50SWQiOiJzVWZHUE1ZMUpjV3J6NVVsWVhHTnhnTGs5c28iLCJhdWQiOiJCYWNrQ2hhbm5lbCIsIm5iZiI6MTcyMTA4NTYzOCwiZ3JhbnRfdHlwZSI6InVybjpvcGVuaWQ6cGFyYW1zOmdyYW50LXR5cGU6Y2liYSIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiXSwiYXV0aF90aW1lIjoxNzIxMDg1NjM4LCJyZWFsbSI6Ii9jb25uZWN0aWQiLCJleHAiOjE3MjEwODkyMzgsImlhdCI6MTcyMTA4NTYzOCwiZXhwaXJlc19pbiI6MzYwMCwianRpIjoiQ1dPTXh5UEpxUzdFR2huNWxzemJjYWF1SlVrIn0.eVG8sBmJY6BvROzDTOjKfGTXzK8SdcYMWbLanrLCgUk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "active": true,
    "scope": "openid profile",
    "realm": "/connectid",
    "client_id": "BackChannel",
    "user_id": "&amp;lt;email address of user&amp;gt;",
    "username": "&amp;lt;email address of user&amp;gt;",
    "token_type": "Bearer",
    "exp": 1721089238,
    "sub": "(usr!nirving@darkedges.com)",
    "iss": "https://xxxx.xxxx.darkedges.com/openam/oauth2",
    "subname": "&amp;lt;email address of user&amp;gt;",
    "authGrantId": "sUfGPMY1JcWrz5UlYXGNxgLk9so",
    "auditTrackingId": "c0fe7702-6515-4a28-b1d6-d631e4ab7160-13922",
    "expires_in": 3356
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;For a Proof of Concept this works for us and should give you the basics for other projects or to demonstrate how it works.&lt;/p&gt;

&lt;p&gt;You can download the Journey and OAuth2Client Amster from &lt;a href="https://gist.github.com/darkedges/e42a70b4c5a76e817154caafb5b7eb92" rel="noopener noreferrer"&gt;https://gist.github.com/darkedges/e42a70b4c5a76e817154caafb5b7eb92&lt;/a&gt;&lt;/p&gt;

</description>
      <category>forgerock</category>
      <category>accessmanager</category>
      <category>pingam</category>
    </item>
  </channel>
</rss>
