{"id":39958,"date":"2020-11-16T00:32:56","date_gmt":"2020-11-16T07:32:56","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/premier-developer\/?p=39958"},"modified":"2020-11-09T11:51:07","modified_gmt":"2020-11-09T18:51:07","slug":"claims-encryption-for-b2c-tokens","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/claims-encryption-for-b2c-tokens\/","title":{"rendered":"Claims encryption for B2C tokens"},"content":{"rendered":"<p><a href=\"https:\/\/www.linkedin.com\/in\/marrochon\/\">Marius Rochon<\/a> shares a sample which Provides Azure B2C JWT token confidentiality by encrypting selected claims prior to token issuance and providing support for their decryption by confidential clients for which these tokens were intended.<\/p>\n<hr \/>\n<pre><code><\/code><\/pre>\n<h2>Claims Encryption<\/h2>\n<pre><code><\/code><\/pre>\n<h2><a id=\"user-content-purpose\" class=\"anchor\" href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption#purpose\" aria-hidden=\"true\"><\/a>Purpose<\/h2>\n<pre><code><\/code><\/pre>\n<p>Provides Azure B2C JWT token confidentiality by encrypting selected claims prior to token issuance and providing support for their decryption by confidential clients for which these tokens were intended.<\/p>\n<pre><code><\/code><\/pre>\n<h2><a id=\"user-content-operation\" class=\"anchor\" href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption#operation\" aria-hidden=\"true\"><\/a>Operation<\/h2>\n<pre><code><\/code><\/pre>\n<p>This system consists of two main components: a web application providing the encryption\/decryption operations and B2C policies calling the encryption operation.<\/p>\n<pre><code><\/code><\/pre>\n<h3><a id=\"user-content-rest-functions\" class=\"anchor\" href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption#rest-functions\" aria-hidden=\"true\"><\/a>REST functions<\/h3>\n<pre><code><\/code><\/pre>\n<p><strong>\/encrypt<\/strong>: encrypt all properties of a JSON object and return a JSON object with same properties with relevant values encrypted. This operation is used by B2C custom policies to encrypt selected claims. The input object <strong>must<\/strong>\u00a0include the\u00a0<em>aud<\/em>\u00a0claim identifying the target application for the token. This is the application which may call the \/decrypt operation. \/encrypt does not use any authentication at this time.<\/p>\n<pre><code><\/code><\/pre>\n<p><strong>Request<\/strong><\/p>\n<pre><code><\/code><\/pre>\n<pre><code>POST \/encrypt\r\nContent-type: application\/json\r\nAccept: application\/json\r\n\r\n{\"aud\":\"&lt;application id&gt;\",\"property1\":\"value1\"}\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<p><strong>Response<\/strong><\/p>\n<pre><code><\/code><\/pre>\n<pre><code>{\"aud\":\"&lt;application id&gt;\",\"property1\":\"CfDJ8OKS0TfF....27hGvaJ0kU3oTTl\"}\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<p><strong>\/decrypt<\/strong>: validates signature of the JWT token submitted in the body of the request and decrypts claims which can be validly decrypted. This operation must be called with an OAuth2 token allowing the caller to call this operation (<em>roles<\/em>\u00a0claim\u00a0<strong>must<\/strong>\u00a0include\u00a0<em>decrypt<\/em>\u00a0role). The caller&#8217;s application id (the\u00a0<em>azp<\/em>\u00a0claim) must be same as the\u00a0<em>aud<\/em>\u00a0claim of the token whose claims need to be decrypted.<\/p>\n<pre><code><\/code><\/pre>\n<p><strong>Request<\/strong><\/p>\n<pre><code><\/code><\/pre>\n<pre><code>POST \/decrypt\r\nContent-type: text\/plain\r\nAccept: application\/json\r\nAuthorization: Bearer eyJ0eXAiOiJKV1QiLC...(authorization to call this service, must include *scope=decrypt*)\r\n\r\neyJ0eXAiOiJKV1QiLC... (token with some encrypted claims)\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<p><strong>Response<\/strong><\/p>\n<pre><code><\/code><\/pre>\n<pre><code>{\"aud\":\"&lt;application id&gt;\",\"property1\":\"value1\"}\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<h3><a id=\"user-content-b2c-custom-policy\" class=\"anchor\" href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption#b2c-custom-policy\" aria-hidden=\"true\"><\/a>B2C custom policy<\/h3>\n<pre><code><\/code><\/pre>\n<p><em>CryptoExtensions.xml<\/em>\u00a0modifies the standard, local account sign-up\/-in journey to encrypt user&#8217;s display name. The call to the encrypt operation looks as follows.\u00a0<strong>Note<\/strong>\u00a0the inclusion of the\u00a0<em>aud<\/em>\u00a0claim in the request.<\/p>\n<pre><code><\/code><\/pre>\n<p>(B2C policies used in this sample use the\u00a0<a href=\"https:\/\/github.com\/mrochon\/b2cief-upload\">IEF upload tool<\/a>\u00a0to resolve tenant name, IEF app ids and symbolic parameters like\u00a0<em>{RESTEncryptUrl}<\/em>\u00a0below).<\/p>\n<pre><code><\/code><\/pre>\n<pre><code>&lt;ClaimsProvider&gt;\r\n  &lt;DisplayName&gt;REST APIs&lt;\/DisplayName&gt;\r\n  &lt;TechnicalProfiles&gt;\r\n    &lt;TechnicalProfile Id=\"REST-Encrypt\"&gt;\r\n      &lt;DisplayName&gt;Encrypt selected claims&lt;\/DisplayName&gt;\r\n      &lt;Protocol Name=\"Proprietary\" Handler=\"Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\" \/&gt;\r\n      &lt;Metadata&gt;\r\n        &lt;Item Key=\"ServiceUrl\"&gt;{RESTEncryptUrl}\/encrypt&lt;\/Item&gt;\r\n        &lt;Item Key=\"SendClaimsIn\"&gt;Body&lt;\/Item&gt;\r\n        &lt;!-- Set AuthenticationType to Basic or ClientCertificate in production environments --&gt;\r\n        &lt;Item Key=\"AuthenticationType\"&gt;None&lt;\/Item&gt;\r\n        &lt;!-- REMOVE the following line in production environments --&gt;\r\n        &lt;Item Key=\"AllowInsecureAuthInProduction\"&gt;true&lt;\/Item&gt;\r\n      &lt;\/Metadata&gt;\r\n      &lt;InputClaims&gt;\r\n        &lt;!-- aud MUST be sent as input claim --&gt;\r\n        &lt;InputClaim ClaimTypeReferenceId=\"aud\" DefaultValue=\"{OIDC:ClientId}\" AlwaysUseDefaultValue=\"true\" \/&gt;          \r\n        &lt;!-- Other claims to be encrypted --&gt;\r\n        &lt;InputClaim ClaimTypeReferenceId=\"displayName\" \/&gt;\r\n      &lt;\/InputClaims&gt;\r\n      &lt;OutputClaims&gt;\r\n        &lt;!-- Returned encrypted claims --&gt;\r\n        &lt;OutputClaim ClaimTypeReferenceId=\"displayName\" \/&gt;\r\n      &lt;\/OutputClaims&gt;\r\n      &lt;UseTechnicalProfileForSessionManagement ReferenceId=\"SM-Noop\" \/&gt;\r\n    &lt;\/TechnicalProfile&gt;\r\n  &lt;\/TechnicalProfiles&gt;\r\n&lt;\/ClaimsProvider&gt;\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<p>You can run this policy using this\u00a0<a href=\"https:\/\/mrochonb2cprod.b2clogin.com\/mrochonb2cprod.onmicrosoft.com\/oauth2\/v2.0\/authorize?p=B2C_1A_CRYPTOsignup_signin&amp;client_id=68f6e047-5204-471a-b94b-b0df615e8ea0&amp;nonce=defaultNonce&amp;redirect_uri=https%3A%2F%2Foidcdebugger.com%2Fdebug&amp;scope=openid&amp;response_type=id_token&amp;prompt=login\" rel=\"nofollow\">link<\/a>. The entered\u00a0<em>Display Name<\/em> will show as encrypted in the displayed token.<\/p>\n<pre><code><\/code><\/pre>\n<h2><a id=\"user-content-deployment\" class=\"anchor\" href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption#deployment\" aria-hidden=\"true\"><\/a>Deployment<\/h2>\n<pre><code><\/code><\/pre>\n<p>You can clone the provided code and deploy it into your own Azure subscription and B2C tenant.<\/p>\n<pre><code><\/code><\/pre>\n<p>I have published the REST functions as a multi-tenant AAD application so you should be able to consent it into your B2C tenant. enter the following request into a browser:<\/p>\n<pre><code><\/code><\/pre>\n<pre><code>https:\/\/login.microsoftonline.com\/&lt;your B2C tenant&gt;.onmicrosoft.com\/oauth2\/v2.0\/authorize?client_id=a4938349-59ca-4238-b70d-1549ed19292d&amp;response_type=code&amp;response_mode=form_post&amp;state=dummy&amp;nonce=dummy&amp;scope=openid\r\n<\/code><\/pre>\n<pre><code><\/code><\/pre>\n<p>Once you sign in and consent, you should see\u00a0<em>TokenEncryption API<\/em>\u00a0in your Enterprise Apps.<\/p>\n<pre><code><\/code><\/pre>\n<p>You will then be able to register your own client applications (recipients of encrypted tokens), set their API Permission to access the\u00a0<em>Token Encryption API<\/em>\u00a0with\u00a0<em>decrypt<\/em>\u00a0application permission, and use client credentials to request a token to call the \/decrypt endpoint.<\/p>\n<pre><code><\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/mrochon\/ClaimsEncryption\">Check out the complete sample on GitHub.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once you sign in and consent, you should see TokenEncryption API in your Enterprise Apps.  You will then be able to register your own client applications (recipients of encrypted tokens), set their API Permission to access the Token Encryption API with decrypt application permission, and use client credentials to request a token.<\/p>\n","protected":false},"author":582,"featured_media":38475,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[25],"tags":[69,1131,10602,213],"class_list":["post-39958","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","tag-azure-ad","tag-b2c","tag-claims","tag-encryption"],"acf":[],"blog_post_summary":"<p>Once you sign in and consent, you should see TokenEncryption API in your Enterprise Apps.  You will then be able to register your own client applications (recipients of encrypted tokens), set their API Permission to access the Token Encryption API with decrypt application permission, and use client credentials to request a token.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39958","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=39958"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39958\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/38475"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=39958"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=39958"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=39958"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}