{"id":1906,"date":"2026-04-06T20:13:59","date_gmt":"2026-04-06T20:13:59","guid":{"rendered":"https:\/\/www.ultrexstaff.com\/?p=1906"},"modified":"2026-04-06T20:13:59","modified_gmt":"2026-04-06T20:13:59","slug":"issuing-cba-certificates-for-new-users-in-microsoft-entra-id","status":"publish","type":"post","link":"https:\/\/www.ultrexstaff.com\/?p=1906","title":{"rendered":"Issuing CBA Certificates for New Users in Microsoft Entra ID"},"content":{"rendered":"\n<p>You&#8217;ve already set up Certificate-Based Authentication (CBA) in your tenant \u2014 your Root CA is uploaded, the authentication method is enabled, and username bindings are configured. Now you need to issue certificates for additional users. This guide covers generating, packaging, and deploying user certificates on both macOS and Windows, plus automating deployment for Windows Entra enrollment.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CBA is enabled in your Entra ID tenant (see the companion article: <em>Setting Up CBA for a New Tenant<\/em>)<\/li>\n\n\n\n<li>Your Root CA files (<code>rootCA.key<\/code> and <code>rootCA.crt<\/code>) are accessible<\/li>\n\n\n\n<li>OpenSSL is installed on your machine<\/li>\n\n\n\n<li>The new user&#8217;s account already exists in Entra ID and you know their UPN (e.g., <code>jane@yourdomain.com<\/code>)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Generate the User&#8217;s Private Key and CSR<\/h2>\n\n\n\n<p>Every user gets their own key pair and certificate. The critical requirement is including the user&#8217;s UPN in the Subject Alternative Name using the Microsoft UPN OID.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">On macOS \/ Linux<\/h3>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl genrsa -out jane-cba.key 2048\n\nopenssl req -new -key jane-cba.key \\\n  -out jane-cba.csr \\\n  -subj \"\/CN=jane@yourdomain.com\" \\\n  -addext \"subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:jane@yourdomain.com\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">On Windows (PowerShell or Git Bash)<\/h3>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl genrsa -out jane-cba.key 2048\n\nopenssl req -new -key jane-cba.key -out jane-cba.csr -subj \"\/CN=jane@yourdomain.com\" -addext \"subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:jane@yourdomain.com\"<\/code><\/pre>\n\n\n\n<p>Replace <code>jane@yourdomain.com<\/code> with the user&#8217;s actual UPN in Entra ID. The UPN must match exactly \u2014 including case \u2014 for the username binding to work.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Sign the Certificate with Your Root CA<\/h2>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl x509 -req -in jane-cba.csr \\\n  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \\\n  -out jane-cba.crt -days 365 -sha256 \\\n  -copy_extensions copyall<\/code><\/pre>\n\n\n\n<p>The <code>-copy_extensions copyall<\/code> flag is essential \u2014 it copies the SAN from the CSR into the signed certificate. Without it, the SAN is silently dropped and CBA authentication will fail.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Bundle into a .pfx File<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">On macOS<\/h3>\n\n\n\n<p>If you&#8217;re running OpenSSL 3.x (most modern Macs), use the <code>-legacy<\/code> flag so macOS Keychain can read the file:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl pkcs12 -export -out jane-cba.pfx \\\n  -inkey jane-cba.key \\\n  -in jane-cba.crt \\\n  -certfile rootCA.crt \\\n  -legacy<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">On Windows<\/h3>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl pkcs12 -export -out jane-cba.pfx -inkey jane-cba.key -in jane-cba.crt -certfile rootCA.crt<\/code><\/pre>\n\n\n\n<p>You&#8217;ll be prompted for an export password. For manual installs, pick something secure. For automated deployments, you&#8217;ll embed this password in your deployment script, so be aware of that tradeoff.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Tip:<\/strong> When prompted interactively, avoid special characters like <code>@<\/code>, <code>!<\/code>, <code>#<\/code> in the password \u2014 shells can interpret them unexpectedly. Stick to alphanumeric passwords to avoid &#8220;MAC verification failed&#8221; headaches.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Import the Certificate on the User&#8217;s Machine<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">On macOS<\/h3>\n\n\n\n<p>Import both the user certificate and the root CA:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>security import jane-cba.pfx -k ~\/Library\/Keychains\/login.keychain-db -P \"YourPassword\"\nsecurity import rootCA.cer -k ~\/Library\/Keychains\/login.keychain-db<\/code><\/pre>\n\n\n\n<p>If the root CA was already imported on this machine (e.g., for another user), the second command will note it&#8217;s a duplicate, which is harmless.<\/p>\n\n\n\n<p><strong>Troubleshooting: &#8220;MAC verification failed during PKCS12 import&#8221;<\/strong><\/p>\n\n\n\n<p>This means the <code>.pfx<\/code> was created with OpenSSL 3.x&#8217;s newer encryption format. Recreate it with the <code>-legacy<\/code> flag (see Step 3).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">On Windows \u2014 Manual Install<\/h3>\n\n\n\n<p><strong>GUI method:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Double-click the <code>.pfx<\/code> file<\/li>\n\n\n\n<li>Select <strong>Current User<\/strong> as the store location<\/li>\n\n\n\n<li>Enter the export password<\/li>\n\n\n\n<li>Accept the defaults and complete the wizard<\/li>\n<\/ol>\n\n\n\n<p><strong>Command line (run as Administrator):<\/strong><\/p>\n\n\n\n<p>powershell<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>certutil -addstore Root rootCA.cer\ncertutil -importpfx jane-cba.pfx<\/code><\/pre>\n\n\n\n<p>You&#8217;ll be prompted for the <code>.pfx<\/code> password.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">On Windows \u2014 Automated via autounattend.xml<\/h3>\n\n\n\n<p>If you&#8217;re deploying Windows via USB with an unattended install, you can import the certificate automatically during setup.<\/p>\n\n\n\n<p><strong>USB folder structure:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ESD-USB:\\\n\u251c\u2500\u2500 autounattend.xml\n\u2514\u2500\u2500 Certs\\\n    \u251c\u2500\u2500 rootCA.cer\n    \u2514\u2500\u2500 jane-cba.pfx<\/code><\/pre>\n\n\n\n<p><strong>Add this to your autounattend.xml<\/strong> inside the appropriate settings pass (e.g., <code>oobeSystem<\/code> or <code>specialize<\/code>):<\/p>\n\n\n\n<p>xml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;RunSynchronousCommand wcm:action=\"add\"&gt;\n    &lt;Order&gt;1&lt;\/Order&gt;\n    &lt;Path&gt;powershell -ExecutionPolicy Bypass -Command \"$d=(Get-Volume -FileSystemLabel 'ESD-USB').DriveLetter; certutil -addstore Root ${d}:\\Certs\\rootCA.cer; certutil -importpfx -p 'YourPassword' ${d}:\\Certs\\jane-cba.pfx\"&lt;\/Path&gt;\n    &lt;Description&gt;Import CBA Certificates&lt;\/Description&gt;\n&lt;\/RunSynchronousCommand&gt;<\/code><\/pre>\n\n\n\n<p>This command dynamically finds the USB drive by its volume label (<code>ESD-USB<\/code>), so it works regardless of which drive letter Windows assigns.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Security note:<\/strong> The <code>.pfx<\/code> password is stored in plaintext in the XML. Treat the USB as a sensitive asset, and consider wiping or rotating the certificate after deployment.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Test the Login<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Fully quit the browser<\/strong> (Cmd+Q on macOS, or close all windows on Windows)<\/li>\n\n\n\n<li>Open the browser and go to <a href=\"https:\/\/login.microsoftonline.com\">https:\/\/login.microsoftonline.com<\/a><\/li>\n\n\n\n<li>Enter the user&#8217;s email address<\/li>\n\n\n\n<li>Choose <strong>&#8220;Use a certificate or smart card&#8221;<\/strong><\/li>\n\n\n\n<li>Select the certificate from the picker dialog<\/li>\n\n\n\n<li>On macOS, enter the Mac login password when the Keychain prompt appears \u2014 click <strong>Always Allow<\/strong> to avoid being asked again<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 6: Set CBA as the Default Sign-In Method<\/h2>\n\n\n\n<p>After a successful first login with the certificate, the user can set CBA as their default authentication method:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to <a href=\"https:\/\/mysignins.microsoft.com\/security-info\">https:\/\/mysignins.microsoft.com\/security-info<\/a><\/li>\n\n\n\n<li>Click <strong>&#8220;Change default sign-in method&#8221;<\/strong><\/li>\n\n\n\n<li>Select <strong>Certificate-based authentication<\/strong><\/li>\n\n\n\n<li>Save<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong> You cannot change another user&#8217;s default sign-in method from the Entra admin center. Each user must set their own default from the My Security Info portal.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Scripting Bulk User Certificate Generation<\/h2>\n\n\n\n<p>If you need to issue certificates for many users at once, here&#8217;s a bash script that automates the process:<\/p>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>#!\/bin\/bash<\/strong>\n\n# List of user UPNs\nUSERS=(\n  \"jane@yourdomain.com\"\n  \"john@yourdomain.com\"\n  \"alex@yourdomain.com\"\n)\n\nPFX_PASSWORD=\"TempDeploy2024\"\n\nfor UPN in \"${USERS&#91;@]}\"; do\n  USERNAME=$(echo \"$UPN\" | cut -d'@' -f1)\n  echo \"Generating certificate for $UPN...\"\n\n  # Generate key\n  openssl genrsa -out \"${USERNAME}-cba.key\" 2048 <strong>2<\/strong>&gt;\/dev\/null\n\n  # Generate CSR with SAN\n  openssl req -new \\\n    -key \"${USERNAME}-cba.key\" \\\n    -out \"${USERNAME}-cba.csr\" \\\n    -subj \"\/CN=${UPN}\" \\\n    -addext \"subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:${UPN}\" \\\n    <strong>2<\/strong>&gt;\/dev\/null\n\n  # Sign with Root CA\n  openssl x509 -req \\\n    -in \"${USERNAME}-cba.csr\" \\\n    -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \\\n    -out \"${USERNAME}-cba.crt\" -days 365 -sha256 \\\n    -copy_extensions copyall \\\n    <strong>2<\/strong>&gt;\/dev\/null\n\n  # Bundle PFX (with -legacy for macOS compatibility)\n  openssl pkcs12 -export \\\n    -out \"${USERNAME}-cba.pfx\" \\\n    -inkey \"${USERNAME}-cba.key\" \\\n    -in \"${USERNAME}-cba.crt\" \\\n    -certfile rootCA.crt \\\n    -legacy \\\n    -password \"pass:${PFX_PASSWORD}\" \\\n    <strong>2<\/strong>&gt;\/dev\/null\n\n  echo \"  Created ${USERNAME}-cba.pfx\"\n\n  # Clean up intermediate files\n  rm -f \"${USERNAME}-cba.key\" \"${USERNAME}-cba.csr\" \"${USERNAME}-cba.crt\"\ndone\n\necho \"Done. All .pfx files ready for deployment.\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Windows equivalent (PowerShell)<\/h3>\n\n\n\n<p>powershell<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$users = @(\n    \"jane@yourdomain.com\",\n    \"john@yourdomain.com\",\n    \"alex@yourdomain.com\"\n)\n\n$pfxPassword = \"TempDeploy2024\"\n\nforeach ($upn in $users) {\n    $username = $upn.Split(\"@\")&#91;0]\n    Write-Host \"Generating certificate for $upn...\"\n\n    openssl genrsa -out \"$username-cba.key\" 2048 2&gt;$null\n\n    openssl req -new `\n        -key \"$username-cba.key\" `\n        -out \"$username-cba.csr\" `\n        -subj \"\/CN=$upn\" `\n        -addext \"subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:$upn\"\n\n    openssl x509 -req `\n        -in \"$username-cba.csr\" `\n        -CA rootCA.crt -CAkey rootCA.key -CAcreateserial `\n        -out \"$username-cba.crt\" -days 365 -sha256 `\n        -copy_extensions copyall\n\n    openssl pkcs12 -export `\n        -out \"$username-cba.pfx\" `\n        -inkey \"$username-cba.key\" `\n        -in \"$username-cba.crt\" `\n        -certfile rootCA.crt `\n        -password \"pass:$pfxPassword\"\n\n    Write-Host \"  Created $username-cba.pfx\"\n\n    Remove-Item \"$username-cba.key\", \"$username-cba.csr\", \"$username-cba.crt\" -ErrorAction SilentlyContinue\n}\n\nWrite-Host \"Done. All .pfx files ready for deployment.\"<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Deploying Certificates via Intune (SCEP\/PKCS)<\/h2>\n\n\n\n<p>For larger organizations, manually distributing <code>.pfx<\/code> files doesn&#8217;t scale. Microsoft Intune supports automated certificate deployment through SCEP and PKCS certificate profiles. The high-level process is:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Set up a certificate connector<\/strong> \u2014 Install the Microsoft Intune Certificate Connector on a Windows Server that has access to your CA<\/li>\n\n\n\n<li><strong>Create a Trusted Certificate profile<\/strong> \u2014 Deploy your root CA certificate to devices<\/li>\n\n\n\n<li><strong>Create a PKCS or SCEP certificate profile<\/strong> \u2014 Configure Intune to automatically issue and deploy user certificates to enrolled devices<\/li>\n<\/ol>\n\n\n\n<p>This is a more complex setup but eliminates the need to manually handle <code>.pfx<\/code> files for each user. Refer to Microsoft&#8217;s documentation on <a href=\"https:\/\/learn.microsoft.com\/en-us\/mem\/intune\/protect\/certificate-connectors\">Intune certificate connectors<\/a> for detailed steps.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Revoking a User&#8217;s Certificate<\/h2>\n\n\n\n<p>If a user leaves the organization or their certificate is compromised, you have several options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Disable the user account<\/strong> in Entra ID \u2014 this prevents sign-in regardless of the certificate<\/li>\n\n\n\n<li><strong>Delete the certificate<\/strong> from the user&#8217;s machine<\/li>\n\n\n\n<li><strong>Set up CRL validation<\/strong> in the CBA configuration and publish a Certificate Revocation List through your CA<\/li>\n<\/ul>\n\n\n\n<p>For immediate revocation without CRL infrastructure, disabling the user account is the fastest approach.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Quick Reference: Commands at a Glance<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Task<\/th><th>Command<\/th><\/tr><\/thead><tbody><tr><td>Generate key<\/td><td><code>openssl genrsa -out user.key 2048<\/code><\/td><\/tr><tr><td>Create CSR with SAN<\/td><td><code>openssl req -new -key user.key -out user.csr -subj \"\/CN=user@domain.com\" -addext \"subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:user@domain.com\"<\/code><\/td><\/tr><tr><td>Sign certificate<\/td><td><code>openssl x509 -req -in user.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out user.crt -days 365 -sha256 -copy_extensions copyall<\/code><\/td><\/tr><tr><td>Create PFX (macOS)<\/td><td><code>openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile rootCA.crt -legacy<\/code><\/td><\/tr><tr><td>Create PFX (Windows)<\/td><td><code>openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile rootCA.crt<\/code><\/td><\/tr><tr><td>Import on macOS<\/td><td><code>security import user.pfx -k ~\/Library\/Keychains\/login.keychain-db -P \"password\"<\/code><\/td><\/tr><tr><td>Import on Windows<\/td><td><code>certutil -importpfx user.pfx<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ve already set up Certificate-Based Authentication (CBA) in your tenant \u2014 your Root CA is uploaded, the authentication method is enabled, and username bindings are configured. Now you need to issue certificates for additional users. This guide covers generating, packaging, and deploying user certificates on both macOS and Windows, plus automating deployment for Windows Entra [&hellip;]<\/p>\n","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1906","post","type-post","status-publish","format-standard","hentry","category-uncategorized","post-preview"],"_links":{"self":[{"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/posts\/1906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1906"}],"version-history":[{"count":1,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/posts\/1906\/revisions"}],"predecessor-version":[{"id":1907,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=\/wp\/v2\/posts\/1906\/revisions\/1907"}],"wp:attachment":[{"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ultrexstaff.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}