{"id":57,"date":"2025-03-30T10:31:32","date_gmt":"2025-03-30T10:31:32","guid":{"rendered":"https:\/\/www.familie-kleinman.nl\/brain\/?p=57"},"modified":"2025-03-31T08:38:19","modified_gmt":"2025-03-31T08:38:19","slug":"oracle-owsm-and-jwt-token-handling","status":"publish","type":"post","link":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/","title":{"rendered":"Oracle OWSM and JWT token handling"},"content":{"rendered":"<p>I&#8217;ll be trying to post several times a week during these first couple of weeks to get some content going. A blog without posts is, well&#8230; basically just a placeholder, right? And I&#8217;m also trying to stay true to one of the words in the subtitle: <em data-start=\"407\" data-end=\"419\">commitment<\/em>. I started this blog for a reason, after all.<\/p>\n<p>So, back on the topic of the day.<\/p>\n<p>In my line of work I do a lot with Oracle SOA\/Middleware and Oracle Service Bus (OSB) and its related products. And because security is always an issue, making your software more secure is always a priority. An option is to secure your flows with JWT tokens handed out by a third party product. Handling this can be done with Oracle Web Services Manager, or OWSM for short. OWSM is part of the Oracle SOA\/Middleware software stack, so it should be quite easy to use, right?<\/p>\n<p>The biggest problem is documentation, and not in the way you think. Oracle is very good at documenting their products \u2014 so good, in fact, that finding what you actually need becomes almost impossible. So the next step is to look for others who&#8217;ve run into the same problem and use their experience as a reference. We found this blog: <a href=\"https:\/\/planetofsolutions.wordpress.com\/2020\/04\/22\/how-to-validate-oauth2-token-in-oracle-service-bus\/\">https:\/\/planetofsolutions.wordpress.com\/2020\/04\/22\/how-to-validate-oauth2-token-in-oracle-service-bus\/<\/a><\/p>\n<p>The biggest problem with using blog posts is that the original author has the context how to interpret the text and the images used. And that context is exactly what made my work a lot harder. So, in this post, I\u2019ll try to clarify all the difficult parts \u2014 and hopefully not step into the same context trap.<\/p>\n<p>It boils down to these two steps.<\/p>\n<ol>\n<li>Attach an OWSM policy to your OSB .proxy ( <strong>oracle\/http_jwt_token_service_policy<\/strong> )<\/li>\n<li>Configure OWSM to verify the integrity of the JWT token that is sent as an HTTP Authorization header in a request to a OSB proxy<\/li>\n<\/ol>\n<p>Step 1 is the easy part, step 2 is where the configuration nightmare begins when you don&#8217;t know exactly what you&#8217;re doing.<\/p>\n<p>The secret lies in understanding what OWSM actually <em data-start=\"304\" data-end=\"310\">does<\/em> before you even start configuring it. Once you know what\u2019s happening under the hood, it becomes much easier to explain <em data-start=\"430\" data-end=\"437\">where<\/em> it needs to be configured. And even more important: how those different parts of the configuration interact with each other!<\/p>\n<h1>JWT<\/h1>\n<p>A JSON Web Token (JWT) consists of three distinct parts.<\/p>\n<ol>\n<li>Header<\/li>\n<li>Payload<\/li>\n<li>Signature<\/li>\n<\/ol>\n<p>For the purpose of this blog post, parts 3 and 2 are the most important. And yes \u2014 I\u2019ll explain in a minute why I\u2019m listing part 3 <em data-start=\"566\" data-end=\"574\">before<\/em> part 2.<\/p>\n<h2>Part 1, is the token valid?<\/h2>\n<p>This is where part 3, <strong>the signature<\/strong>, of the token comes into play. The very first thing OWSM needs to do is verify that the signature is valid. A JWT is signed using a private key, and to verify it, OWSM needs the <strong data-start=\"836\" data-end=\"858\">public certificate<\/strong> \u2014 or more precisely, the <strong data-start=\"884\" data-end=\"919\">entire public certificate chain<\/strong> \u2014 to be imported and available.<\/p>\n<h2>Part 2, is the issuer trusted?<\/h2>\n<p class=\"\" data-start=\"323\" data-end=\"364\">Great \u2014 the signature is valid. Now what? This is where <strong data-start=\"380\" data-end=\"390\">part 2<\/strong>, the <strong data-start=\"396\" data-end=\"407\">payload<\/strong>, comes into play. OWSM somehow needs to know whether the issuer of the JWT token can actually be <em data-start=\"505\" data-end=\"514\">trusted<\/em>.<\/p>\n<p class=\"\" data-start=\"517\" data-end=\"661\">This is typically done by validating the <strong data-start=\"558\" data-end=\"564\">CN<\/strong> (Common Name) or <strong data-start=\"582\" data-end=\"588\">DN<\/strong> (Distinguished Name) from the public certificate used to sign the token. And this is where things can start to get a little confusing&#8230; But don\u2019t worry \u2014 I\u2019ll get back to this in more detail soon.<\/p>\n<h2 data-start=\"517\" data-end=\"661\">Part 3, is the token expired?<\/h2>\n<p class=\"\" data-start=\"307\" data-end=\"420\">At this point, OWSM starts looking into the <strong data-start=\"351\" data-end=\"362\">payload<\/strong> itself. The first field it checks is the <code data-start=\"406\" data-end=\"413\">\"exp\"<\/code> claim.<\/p>\n<p class=\"\" data-start=\"422\" data-end=\"663\">This field contains the <strong data-start=\"446\" data-end=\"465\">expiration time<\/strong> of the token, expressed in <strong data-start=\"493\" data-end=\"512\">Unix Epoch time<\/strong> \u2014 the number of seconds since January 1, 1970. If the current time is greater than this value, the token is considered expired and will be rejected.<\/p>\n<h2>Part 4, is the audience trusted<\/h2>\n<p class=\"\" data-start=\"261\" data-end=\"322\"><strong data-start=\"261\" data-end=\"322\">OWSM will now check the <code data-start=\"287\" data-end=\"294\">\"aud\"<\/code> field inside the payload.<\/strong><\/p>\n<p class=\"\" data-start=\"324\" data-end=\"455\">This field tells you <strong data-start=\"345\" data-end=\"352\">who<\/strong> the token is intended for. In other words: <em data-start=\"398\" data-end=\"455\">&#8220;This token was issued specifically for application X.&#8221;\u00a0<\/em>OWSM (or any secure service) can be configured to check whether the <code data-start=\"525\" data-end=\"532\">\"aud\"<\/code> value matches the expected identifier of the service. If it doesn\u2019t match, the token is considered <strong data-start=\"634\" data-end=\"645\">invalid<\/strong> \u2014 even if the signature is correct and the token hasn\u2019t expired.<\/p>\n<p class=\"\" data-start=\"712\" data-end=\"848\">This is a useful way to prevent token misuse \u2014 for example, if someone tries to use a token meant for <em data-start=\"814\" data-end=\"825\">Service A<\/em> to access <em data-start=\"836\" data-end=\"847\">Service B<\/em>.<\/p>\n<p class=\"\" data-start=\"855\" data-end=\"946\"><strong data-start=\"855\" data-end=\"894\">But there\u2019s a huge catch with this.<\/strong><br data-start=\"894\" data-end=\"897\" \/><em data-start=\"897\" data-end=\"946\">(See the note at the bottom of this blog post.)<\/em><\/p>\n<p class=\"\" data-start=\"948\" data-end=\"1099\">It means we somehow need to maintain a <strong data-start=\"987\" data-end=\"1016\">list of trusted audiences<\/strong> somewhere in the OWSM configuration \u2014 and that\u2019s where things start to get tricky.<\/p>\n<h2 data-start=\"948\" data-end=\"1099\">Part 5, subject check<\/h2>\n<p class=\"\" data-start=\"317\" data-end=\"373\"><strong data-start=\"317\" data-end=\"373\">And this is where Oracle deviates from the standard.<\/strong><\/p>\n<p class=\"\" data-start=\"375\" data-end=\"570\">According to the JWT specification, there\u2019s an optional field called <code data-start=\"444\" data-end=\"451\">\"sub\"<\/code> \u2014 short for <strong data-start=\"464\" data-end=\"475\">subject<\/strong>. It\u2019s meant to identify the principal (usually the user or system) that the token refers to.<\/p>\n<p class=\"\" data-start=\"572\" data-end=\"624\"><strong data-start=\"572\" data-end=\"584\">Optional<\/strong>, as in: nice to have, but not required. Except\u2026 Oracle made it mandatory<\/p>\n<p class=\"\" data-start=\"660\" data-end=\"874\">At least in the version of OWSM we use, the <code data-start=\"713\" data-end=\"720\">\"sub\"<\/code> field is treated as <strong data-start=\"742\" data-end=\"755\">mandatory<\/strong> \u2014 and this <strong data-start=\"767\" data-end=\"797\">wasn\u2019t documented anywhere<\/strong> at the time.\u00a0 By now you can find a support document on Oracle Support.<\/p>\n<p class=\"\" data-start=\"876\" data-end=\"931\">Let\u2019s just say: that one took us a while to figure out.<\/p>\n<p data-start=\"876\" data-end=\"931\">This does mean that we need to configure the subject somewhere!<\/p>\n<h1 data-start=\"876\" data-end=\"931\">Summary #1 &#8211; OWSM validation flow<\/h1>\n<p class=\"\" data-start=\"349\" data-end=\"407\">OWSM will go through the following five validation layers:<\/p>\n<ol data-start=\"409\" data-end=\"823\">\n<li class=\"\" data-start=\"409\" data-end=\"478\">\n<p class=\"\" data-start=\"412\" data-end=\"478\"><strong data-start=\"412\" data-end=\"435\">Is the token valid?<\/strong><br data-start=\"435\" data-end=\"438\" \/>\u2003\u2192 Signature check using the public key.<\/p>\n<\/li>\n<li class=\"\" data-start=\"480\" data-end=\"548\">\n<p class=\"\" data-start=\"483\" data-end=\"548\"><strong data-start=\"483\" data-end=\"509\">Is the issuer trusted?<\/strong><br data-start=\"509\" data-end=\"512\" \/>\u2003\u2192 Based on the certificate\u2019s CN\/DN.<\/p>\n<\/li>\n<li class=\"\" data-start=\"550\" data-end=\"627\">\n<p class=\"\" data-start=\"553\" data-end=\"627\"><strong data-start=\"553\" data-end=\"578\">Is the token expired?<\/strong><br data-start=\"578\" data-end=\"581\" \/>\u2003\u2192 Checked via the <code data-start=\"600\" data-end=\"607\">\"exp\"<\/code> (expiration) claim.<\/p>\n<\/li>\n<li class=\"\" data-start=\"629\" data-end=\"711\">\n<p class=\"\" data-start=\"632\" data-end=\"711\"><strong data-start=\"632\" data-end=\"660\">Is the audience trusted?<\/strong><br data-start=\"660\" data-end=\"663\" \/>\u2003\u2192 Checked via the <code data-start=\"682\" data-end=\"689\">\"aud\"<\/code> claim, if configured.<\/p>\n<\/li>\n<li class=\"\" data-start=\"713\" data-end=\"823\">\n<p class=\"\" data-start=\"716\" data-end=\"823\"><strong data-start=\"716\" data-end=\"743\">Is the subject trusted?<\/strong><br data-start=\"743\" data-end=\"746\" \/>\u2003\u2192 The <code data-start=\"753\" data-end=\"760\">\"sub\"<\/code> claim must be present \u2014 and is it configured.<\/p>\n<\/li>\n<\/ol>\n<h1>Configuration<\/h1>\n<h2>Prerequisites<\/h2>\n<ul>\n<li class=\"\" data-start=\"323\" data-end=\"495\">\n<p class=\"\" data-start=\"326\" data-end=\"495\"><strong data-start=\"326\" data-end=\"370\">Obtain the full public certificate chain<\/strong> from your JWT token provider.<br data-start=\"400\" data-end=\"403\" \/>\u2003You can usually use your browser to download the entire chain (via the HTTPS padlock icon).<\/p>\n<\/li>\n<li class=\"\" data-start=\"497\" data-end=\"659\">\n<p class=\"\" data-start=\"500\" data-end=\"659\"><strong data-start=\"500\" data-end=\"536\">Get at least one valid JWT token<\/strong> that will be used for testing.<br data-start=\"567\" data-end=\"570\" \/>\u2003Open it in a tool that can visualize the payload, e.g. <a class=\"\" href=\"https:\/\/jwt.io\" target=\"_new\" rel=\"noopener\" data-start=\"626\" data-end=\"658\">https:\/\/jwt.io<\/a>.<\/p>\n<\/li>\n<li class=\"\" data-start=\"661\" data-end=\"786\">\n<p class=\"\" data-start=\"664\" data-end=\"719\"><strong data-start=\"664\" data-end=\"719\">Take note of the following fields from the payload:<\/strong><\/p>\n<ul data-start=\"723\" data-end=\"786\">\n<li class=\"\" data-start=\"723\" data-end=\"753\">\n<p class=\"\" data-start=\"725\" data-end=\"753\">The <code data-start=\"729\" data-end=\"736\">\"aud\"<\/code> (audience) claim<\/p>\n<\/li>\n<li>The <code data-start=\"729\" data-end=\"736\">\"iss\"<\/code> (issuer) claim<\/li>\n<li class=\"\" data-start=\"757\" data-end=\"786\">\n<p class=\"\" data-start=\"759\" data-end=\"786\">The <code data-start=\"763\" data-end=\"770\">\"sub\"<\/code> (subject) claim<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Step 1, import the certificates<\/h2>\n<ul>\n<li class=\"\" data-start=\"834\" data-end=\"932\">\n<p class=\"\" data-start=\"837\" data-end=\"932\">Open Oracle Enterprise Manager (EM) by pointing your browser to:<br data-start=\"901\" data-end=\"904\" \/>\u2003<code data-start=\"905\" data-end=\"932\">http:\/\/yourserver:port\/em<\/code><\/p>\n<\/li>\n<li class=\"\" data-start=\"934\" data-end=\"994\">\n<p class=\"\" data-start=\"937\" data-end=\"994\">Open the menu and navigate to:<br data-start=\"967\" data-end=\"970\" \/>\u2003<strong data-start=\"971\" data-end=\"994\">Security \u2192 Keystore<\/strong><\/p>\n<\/li>\n<li class=\"\" data-start=\"996\" data-end=\"1129\">\n<p class=\"\" data-start=\"999\" data-end=\"1129\">Under the <strong data-start=\"1009\" data-end=\"1019\"><code data-start=\"1011\" data-end=\"1017\">owsm<\/code><\/strong> section, check if there\u2019s a keystore named <code data-start=\"1063\" data-end=\"1075\">\"keystore\"<\/code>. If it is not there create it.<br data-start=\"1076\" data-end=\"1079\" \/>\u2003&gt; <em data-start=\"1082\" data-end=\"1129\">Note: If allowed, I\u2019ll add screenshots later.<\/em><\/p>\n<\/li>\n<li data-start=\"996\" data-end=\"1129\">Import the public certificate chain. After importing the client certificate of your JWT token provider please make a copy of the CN (common name ) of the certificate as you will need this in the next step!<\/li>\n<\/ul>\n<h2>Step 2, configure trust for the issuer<\/h2>\n<ul>\n<li>Navigate to <strong data-start=\"318\" data-end=\"346\">WSM Domain Configuration<\/strong> in Oracle Enterprise Manager.<\/li>\n<li>Switch to the <strong data-start=\"396\" data-end=\"414\">Authentication<\/strong> tab.<\/li>\n<li>Locate the <strong data-start=\"436\" data-end=\"449\">JWT Trust<\/strong> section.<\/li>\n<li>Add a new entry:\n<ul>\n<li><strong>Issuer name<\/strong>, this has to be the exact <code data-start=\"729\" data-end=\"736\">\"iss\"<\/code> from the example JWT token.<\/li>\n<li><strong>Issuer DN<\/strong>, this is the CN you saved before!<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong data-start=\"646\" data-end=\"655\">Note:<\/strong><br data-start=\"655\" data-end=\"658\" \/>The blog post I mentioned earlier claims you need to do a whole lot more here \u2014 but that\u2019s not the case!\u00a0 This one step is enough to tell OWSM which issuer(s) to trust based on their certificate.<\/p>\n<p>Now OWSM knows how to connect the certificate from the token to the right certificate chain<\/p>\n<h2>Step 3, audience configuration<\/h2>\n<p>For some reason, this step can\u2019t be performed through the browser interface. It has to be done via the WLST console instead.<\/p>\n<p>Please read this full block \u2014 including the comments \u2014 before entering any commands in WLST.<\/p>\n<ul>\n<li>Open WLST and connect to your server<\/li>\n<\/ul>\n<pre>beginWSMSession()\r\nlistWSMTokenIssuerTrustDocuments(detail='true')\r\nselectWSMTokenIssuerTrustDocument(\"tokenissuertrust-WLS-osb_domain\")\r\naddWSMTokenIssuerTrustRP(\"literal.jwt\", \"&lt;iss&gt;\", [\"&lt;aud&gt;\"])\r\ndisplayWSMTokenIssuerTrustRP(\"literal.jwt\", \"&lt;iss&gt;\")\r\ncommitWSMSession()<\/pre>\n<h3>Explanation<\/h3>\n<ul>\n<li class=\"\" data-start=\"846\" data-end=\"1109\">\n<p class=\"\" data-start=\"848\" data-end=\"1109\"><code data-start=\"848\" data-end=\"884\">listWSMTokenIssuerTrustDocuments()<\/code><br data-start=\"884\" data-end=\"887\" \/>This command lists all available Trust Documents.<br data-start=\"938\" data-end=\"941\" \/>Depending on your setup, you might see something like:<br data-start=\"997\" data-end=\"1000\" \/><code data-start=\"1002\" data-end=\"1035\">tokenissuertrust-WLS-osb_domain<\/code>,<br data-start=\"1036\" data-end=\"1039\" \/><code data-start=\"1041\" data-end=\"1082\">tokenissuertrust-WLS-osb_domain_cluster<\/code>,<br data-start=\"1083\" data-end=\"1086\" \/>or something similar.<\/p>\n<\/li>\n<li class=\"\" data-start=\"1111\" data-end=\"1224\">\n<p class=\"\" data-start=\"1113\" data-end=\"1224\"><code data-start=\"1113\" data-end=\"1153\">selectWSMTokenIssuerTrustDocument(...)<\/code><br data-start=\"1153\" data-end=\"1156\" \/>Use this to select the correct Trust Document from the list above.<\/p>\n<\/li>\n<li class=\"\" data-start=\"1226\" data-end=\"1437\">\n<p class=\"\" data-start=\"1228\" data-end=\"1437\"><code data-start=\"1228\" data-end=\"1285\">addWSMTokenIssuerTrustRP(\"literal.jwt\", \"iss\", [\"aud\"])<\/code><br data-start=\"1285\" data-end=\"1288\" \/>Here you\u2019re literally stating:<br data-start=\"1320\" data-end=\"1323\" \/><em data-start=\"1325\" data-end=\"1437\">&#8220;When I receive a token from this issuer (<code data-start=\"1368\" data-end=\"1373\">iss<\/code>) and it contains this audience (<code data-start=\"1406\" data-end=\"1411\">aud<\/code>), then I will trust it.&#8221;<\/em><\/p>\n<\/li>\n<\/ul>\n<p>In this step, you\u2019re connecting the <code data-start=\"401\" data-end=\"406\">aud<\/code> claim from the token to the JWT Trust entry you defined in the previous step.<\/p>\n<p><strong>Example:<\/strong><\/p>\n<p>You decoded a JWT token and it contains:<\/p>\n<pre>{\r\n\"iss\": \"https:\/\/auth.example.com\/issuer\/jwt\/token\/something\",\r\n\"sub\": \"user12345\",\r\n\"aud\": \"00000003-0000-0ff1-ce00-000000000000\",\r\n\"exp\": 1711854000,\r\n\"iat\": 1711850400,\r\n\"nbf\": 1711850400,\r\n\"jti\": \"abc123xyz\",\r\n\"scope\": \"read:all write:limited\",\r\n\"role\": \"admin\"\r\n}<\/pre>\n<p><strong>In step 2 you configured:<\/strong><\/p>\n<ul>\n<li>Issuer name: https:\/\/auth.example.com\/issuer\/jwt\/token\/something<\/li>\n<li>Issuer DN: The public Common Name<\/li>\n<\/ul>\n<p><strong>In step 3 you will do:<\/strong><\/p>\n<pre>beginWSMSession()\r\nlistWSMTokenIssuerTrustDocuments(detail='true')\r\nselectWSMTokenIssuerTrustDocument(\"tokenissuertrust-WLS-osb_domain\")\r\naddWSMTokenIssuerTrustRP(\"literal.jwt\", \r\n                         \"<strong>https:\/\/auth.example.com\/issuer\/jwt\/token\/something<\/strong>\", \r\n                         [\"<strong>00000003-0000-0ff1-ce00-000000000000<\/strong>\"]\r\n                        )\r\ndisplayWSMTokenIssuerTrustRP(\"literal.jwt\", \r\n                             \"<strong>https:\/\/auth.example.com\/issuer\/jwt\/token\/something<\/strong>\"\r\n                            )\r\ncommitWSMSession()<\/pre>\n<p>I hope this clarifies how to do this part of the configuration, this took me a long while to figure out.<\/p>\n<h2>Step 4, subject configuration<\/h2>\n<ul>\n<li class=\"\" data-start=\"466\" data-end=\"559\">\n<p class=\"\" data-start=\"469\" data-end=\"559\">Open the <strong data-start=\"478\" data-end=\"505\">Oracle WebLogic Console<\/strong> by navigating to:<br data-start=\"523\" data-end=\"526\" \/>\u2003<code data-start=\"527\" data-end=\"559\">http:\/\/yourserver:port\/console<\/code><\/p>\n<\/li>\n<li class=\"\" data-start=\"561\" data-end=\"609\">\n<p class=\"\" data-start=\"564\" data-end=\"609\">Go to <strong data-start=\"570\" data-end=\"582\">Security<\/strong>, and click on <strong data-start=\"597\" data-end=\"608\">myrealm<\/strong>.<\/p>\n<\/li>\n<li class=\"\" data-start=\"611\" data-end=\"707\">\n<p class=\"\" data-start=\"614\" data-end=\"707\">Add a new <strong data-start=\"624\" data-end=\"632\">user<\/strong> with the exact value used in the <code data-start=\"666\" data-end=\"673\">\"sub\"<\/code> (subject) field of the JWT token.<\/p>\n<\/li>\n<\/ul>\n<p><strong data-start=\"711\" data-end=\"720\">Note:<\/strong><br data-start=\"720\" data-end=\"723\" \/>No additional roles or permissions are needed for this user.\u00a0 OWSM only checks whether the user exists in the security realm \u2014 that&#8217;s it!<\/p>\n<h1>Summary #2, OWSM configuration<\/h1>\n<ol>\n<li class=\"\" data-start=\"264\" data-end=\"332\">\n<p class=\"\" data-start=\"267\" data-end=\"332\"><strong data-start=\"267\" data-end=\"306\">Import the public certificate chain<\/strong> into the OWSM keystore.<\/p>\n<\/li>\n<li class=\"\" data-start=\"333\" data-end=\"423\">\n<p class=\"\" data-start=\"336\" data-end=\"423\"><strong data-start=\"336\" data-end=\"366\">Configure JWT issuer trust<\/strong> by linking the certificate\u2019s CN\/DN to the issuer name.<\/p>\n<\/li>\n<li class=\"\" data-start=\"424\" data-end=\"505\">\n<p class=\"\" data-start=\"427\" data-end=\"505\"><strong data-start=\"427\" data-end=\"458\">Configure trusted audiences<\/strong> by associating them with the correct issuer.<\/p>\n<\/li>\n<li class=\"\" data-start=\"506\" data-end=\"667\">\n<p class=\"\" data-start=\"509\" data-end=\"667\"><strong data-start=\"509\" data-end=\"523\">Add a user<\/strong> to your WebLogic security realm matching the <code data-start=\"569\" data-end=\"574\">sub<\/code> (subject) value in the token.<br data-start=\"604\" data-end=\"607\" \/>\u2003\u2192 <em data-start=\"610\" data-end=\"667\">No roles or permissions required \u2014 existence is enough!<\/em><\/p>\n<\/li>\n<\/ol>\n<h1>OSB<\/h1>\n<p>Now you can add the <strong>oracle\/http_jwt_token_service_policy<\/strong> policy to a proxy and test it.<\/p>\n<h1>Testing<\/h1>\n<p class=\"\" data-start=\"253\" data-end=\"327\">I prefer testing using <strong data-start=\"276\" data-end=\"286\">SoapUI<\/strong> \u2014 it\u2019s quick, flexible, and easy to use.<\/p>\n<ol data-start=\"329\" data-end=\"552\">\n<li class=\"\" data-start=\"329\" data-end=\"392\">\n<p class=\"\" data-start=\"332\" data-end=\"392\">Import your <strong data-start=\"344\" data-end=\"352\">WSDL<\/strong> or <strong data-start=\"356\" data-end=\"377\">REST endpoint URI<\/strong> into SoapUI.<\/p>\n<\/li>\n<li class=\"\" data-start=\"393\" data-end=\"517\">\n<p class=\"\" data-start=\"396\" data-end=\"427\">Add a custom <strong data-start=\"409\" data-end=\"424\">HTTP header<\/strong>:<\/p>\n<ul data-start=\"431\" data-end=\"517\">\n<li class=\"\" data-start=\"431\" data-end=\"460\">\n<p class=\"\" data-start=\"433\" data-end=\"460\"><strong data-start=\"433\" data-end=\"442\">Name:<\/strong> <code data-start=\"443\" data-end=\"458\">Authorization<\/code><\/p>\n<\/li>\n<li class=\"\" data-start=\"464\" data-end=\"517\">\n<p class=\"\" data-start=\"466\" data-end=\"517\"><strong data-start=\"466\" data-end=\"476\">Value:<\/strong> <code data-start=\"477\" data-end=\"517\">Bearer &lt;your base64-encoded JWT token&gt;<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li class=\"\" data-start=\"519\" data-end=\"552\">\n<p class=\"\" data-start=\"522\" data-end=\"552\"><strong data-start=\"522\" data-end=\"552\">Send the request and test!<\/strong><\/p>\n<\/li>\n<\/ol>\n<p>If all goes well you should get a HTTP 200 status code in response.<\/p>\n<h1>Errors?!?!<\/h1>\n<p class=\"\" data-start=\"353\" data-end=\"549\">While testing, you can \u2014 and probably <em data-start=\"391\" data-end=\"397\">will<\/em> \u2014 run into various <code data-start=\"417\" data-end=\"428\">WSM-xxxxx<\/code> errors in your logs. Listing them all here would make this blog post even longer. So I\u2019ll cover those in a <strong data-start=\"576\" data-end=\"593\">separate post<\/strong>, where I go into the most common error messages, what they actually mean, and \u2014 more importantly \u2014 how to fix them.<\/p>\n<h1 data-start=\"390\" data-end=\"523\">Note: OSB and &#8220;audience enforcement&#8221;<\/h1>\n<p class=\"\" data-start=\"538\" data-end=\"638\">What if <em data-start=\"546\" data-end=\"551\">all<\/em> your requests come from the same JWT issuer \u2014 even if they use different <code data-start=\"625\" data-end=\"630\">aud<\/code> values?<\/p>\n<p class=\"\" data-start=\"640\" data-end=\"767\">Now combine that with Oracle Service Bus, where all services are secured using the same <code data-start=\"728\" data-end=\"766\">oracle\/http_jwt_token_service_policy<\/code>.<\/p>\n<p class=\"\" data-start=\"769\" data-end=\"785\">See the problem?<\/p>\n<p class=\"\" data-start=\"787\" data-end=\"1069\">There\u2019s <strong data-start=\"795\" data-end=\"820\">no built-in mechanism<\/strong> in OWSM to enforce that a specific OSB proxy only accepts tokens with a certain <code data-start=\"901\" data-end=\"906\">aud<\/code> value. Since the policy is reused across proxies, OWSM will happily validate the signature and accept <em data-start=\"1011\" data-end=\"1016\">any<\/em> token from that issuer \u2014 regardless of the audience or other claims in the token itself.<\/p>\n<p class=\"\" data-start=\"787\" data-end=\"1069\">But, there might be a solution! I will write a separate blog post for that soon!<\/p>\n<h1 data-start=\"787\" data-end=\"1069\">Conclusion<\/h1>\n<p data-start=\"787\" data-end=\"1069\">If this post helped you get through the proverbial jungle that is OSB, OWSM policies &amp; JWT tokens, let me know!<\/p>\n<p data-start=\"787\" data-end=\"1069\">Brain out!<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ll be trying to post several times a week during these first couple of weeks to get some content going. A blog without posts is, well&#8230; basically just a placeholder, right? And I&#8217;m also trying to stay true to one of the words in the subtitle: commitment. I started this blog for a reason, after&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[36,19,29,37,23,33,24,20,35,30,27,16,17,18,32,31,25,26,21,34,28],"class_list":["post-57","post","type-post","status-publish","format-standard","hentry","category-coding","tag-access-control","tag-audience","tag-authorization-header","tag-bearer","tag-claim","tag-enterprise-manager","tag-issuer","tag-jwt","tag-jwt-troubleshooting","tag-jwt-validation","tag-keystore","tag-oracle","tag-osb","tag-owsm","tag-policy","tag-security","tag-soapui","tag-subject","tag-token","tag-weblogic","tag-wlst"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Oracle OWSM and JWT token handling - Brain&#039;s Ramblings<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Oracle OWSM and JWT token handling - Brain&#039;s Ramblings\" \/>\n<meta property=\"og:description\" content=\"I&#8217;ll be trying to post several times a week during these first couple of weeks to get some content going. A blog without posts is, well&#8230; basically just a placeholder, right? And I&#8217;m also trying to stay true to one of the words in the subtitle: commitment. I started this blog for a reason, after...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/\" \/>\n<meta property=\"og:site_name\" content=\"Brain&#039;s Ramblings\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-30T10:31:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-31T08:38:19+00:00\" \/>\n<meta name=\"author\" content=\"Brain\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Brain\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/\"},\"author\":{\"name\":\"Brain\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#\\\/schema\\\/person\\\/24700e1628cfd605409636397a9bb6ab\"},\"headline\":\"Oracle OWSM and JWT token handling\",\"datePublished\":\"2025-03-30T10:31:32+00:00\",\"dateModified\":\"2025-03-31T08:38:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/\"},\"wordCount\":1805,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#\\\/schema\\\/person\\\/24700e1628cfd605409636397a9bb6ab\"},\"keywords\":[\"Access control\",\"Audience\",\"Authorization header\",\"Bearer\",\"Claim\",\"Enterprise Manager\",\"Issuer\",\"JWT\",\"JWT troubleshooting\",\"JWT validation\",\"Keystore\",\"Oracle\",\"OSB\",\"OWSM\",\"Policy\",\"Security\",\"SoapUI\",\"Subject\",\"Token\",\"WebLogic\",\"WLST\"],\"articleSection\":[\"Coding\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/\",\"url\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/\",\"name\":\"Oracle OWSM and JWT token handling - Brain&#039;s Ramblings\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#website\"},\"datePublished\":\"2025-03-30T10:31:32+00:00\",\"dateModified\":\"2025-03-31T08:38:19+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/2025\\\/03\\\/30\\\/oracle-owsm-and-jwt-token-handling\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Oracle OWSM and JWT token handling\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#website\",\"url\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/\",\"name\":\"Brain's Ramblings\",\"description\":\"Code, commitment, caffeine, and the odd mindfart\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#\\\/schema\\\/person\\\/24700e1628cfd605409636397a9bb6ab\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/#\\\/schema\\\/person\\\/24700e1628cfd605409636397a9bb6ab\",\"name\":\"Brain\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/brain_brain.png\",\"url\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/brain_brain.png\",\"contentUrl\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/brain_brain.png\",\"width\":1024,\"height\":1024,\"caption\":\"Brain\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/brain_brain.png\"},\"sameAs\":[\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\"],\"url\":\"https:\\\/\\\/www.familie-kleinman.nl\\\/brain\\\/index.php\\\/author\\\/brain\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Oracle OWSM and JWT token handling - Brain&#039;s Ramblings","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/","og_locale":"en_US","og_type":"article","og_title":"Oracle OWSM and JWT token handling - Brain&#039;s Ramblings","og_description":"I&#8217;ll be trying to post several times a week during these first couple of weeks to get some content going. A blog without posts is, well&#8230; basically just a placeholder, right? And I&#8217;m also trying to stay true to one of the words in the subtitle: commitment. I started this blog for a reason, after...","og_url":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/","og_site_name":"Brain&#039;s Ramblings","article_published_time":"2025-03-30T10:31:32+00:00","article_modified_time":"2025-03-31T08:38:19+00:00","author":"Brain","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Brain","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/#article","isPartOf":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/"},"author":{"name":"Brain","@id":"https:\/\/www.familie-kleinman.nl\/brain\/#\/schema\/person\/24700e1628cfd605409636397a9bb6ab"},"headline":"Oracle OWSM and JWT token handling","datePublished":"2025-03-30T10:31:32+00:00","dateModified":"2025-03-31T08:38:19+00:00","mainEntityOfPage":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/"},"wordCount":1805,"commentCount":1,"publisher":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/#\/schema\/person\/24700e1628cfd605409636397a9bb6ab"},"keywords":["Access control","Audience","Authorization header","Bearer","Claim","Enterprise Manager","Issuer","JWT","JWT troubleshooting","JWT validation","Keystore","Oracle","OSB","OWSM","Policy","Security","SoapUI","Subject","Token","WebLogic","WLST"],"articleSection":["Coding"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/","url":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/","name":"Oracle OWSM and JWT token handling - Brain&#039;s Ramblings","isPartOf":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/#website"},"datePublished":"2025-03-30T10:31:32+00:00","dateModified":"2025-03-31T08:38:19+00:00","breadcrumb":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/2025\/03\/30\/oracle-owsm-and-jwt-token-handling\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.familie-kleinman.nl\/brain\/"},{"@type":"ListItem","position":2,"name":"Oracle OWSM and JWT token handling"}]},{"@type":"WebSite","@id":"https:\/\/www.familie-kleinman.nl\/brain\/#website","url":"https:\/\/www.familie-kleinman.nl\/brain\/","name":"Brain's Ramblings","description":"Code, commitment, caffeine, and the odd mindfart","publisher":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/#\/schema\/person\/24700e1628cfd605409636397a9bb6ab"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.familie-kleinman.nl\/brain\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.familie-kleinman.nl\/brain\/#\/schema\/person\/24700e1628cfd605409636397a9bb6ab","name":"Brain","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.familie-kleinman.nl\/brain\/wp-content\/uploads\/2025\/04\/brain_brain.png","url":"https:\/\/www.familie-kleinman.nl\/brain\/wp-content\/uploads\/2025\/04\/brain_brain.png","contentUrl":"https:\/\/www.familie-kleinman.nl\/brain\/wp-content\/uploads\/2025\/04\/brain_brain.png","width":1024,"height":1024,"caption":"Brain"},"logo":{"@id":"https:\/\/www.familie-kleinman.nl\/brain\/wp-content\/uploads\/2025\/04\/brain_brain.png"},"sameAs":["https:\/\/www.familie-kleinman.nl\/brain"],"url":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/author\/brain\/"}]}},"_links":{"self":[{"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/posts\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":11,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/posts\/57\/revisions"}],"predecessor-version":[{"id":70,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/posts\/57\/revisions\/70"}],"wp:attachment":[{"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/media?parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/categories?post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.familie-kleinman.nl\/brain\/index.php\/wp-json\/wp\/v2\/tags?post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}