[{"data":1,"prerenderedAt":35},["ShallowReactive",2],{"post-data-personal-access-tokens-headless-ci-cd-and-the-30-day-hard-limit":3},{"post":4,"relatedPosts":19},{"id":5,"title":6,"content":7,"hashtags":8,"coverImage":15,"createdAt":16,"seoTitle":17,"seoDescription":18},"dLLrAXGo6OCXzFkEB2EE","Personal Access Tokens, Headless CI\u002FCD, and the 30-Day Hard Limit","\u003Cp data-path-to-node=\"1\">As we continue to expand the Ennote CLI's capabilities, a critical requirement for our enterprise users has been the ability to automate secret injection in headless environments. Today, we are bridging the gap between our interactive SSO flows and machine-driven automation by introducing \u003Cstrong data-path-to-node=\"1\" data-index-in-node=\"290\">Personal Access Tokens (PATs)\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp id=\"p-rc_9301a8bdc172ea32-49\" data-path-to-node=\"2\">\u003Cspan data-path-to-node=\"2,0\">Personal Access Tokens allow you to securely authenticate with the Ennote CLI directly without needing an interactive browser session\u003C\u002Fspan>\u003Cspan data-path-to-node=\"2,1\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003Csup class=\"superscript\">\u003C!---->\u003C\u002Fsup>\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fspan>\u003Cspan data-path-to-node=\"2,2\">.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp data-path-to-node=\"3\">Here is an architectural breakdown of how PATs integrate into your DevSecOps pipelines, and why we made specific \"Security by Design\" decisions regarding their lifecycle.\u003C\u002Fp>\n\u003Ch3 data-path-to-node=\"5\">Seamless CI\u002FCD Integration\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"6\">In local development, the Ennote CLI uses an OAuth 2.0 PKCE flow to bind an ephemeral session to the developer's OS Keyring. However, CI\u002FCD runners (like GitHub Actions, GitLab CI, or Jenkins) are headless and ephemeral by nature. They cannot execute interactive browser logins.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"7\">With the introduction of PATs, you can now provision a cryptographic token directly from your User Settings -&gt; Security dashboard.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"8\">Once generated, injecting secrets into a CI\u002FCD pipeline is as simple as exposing the token via the \u003Ccode data-path-to-node=\"8\" data-index-in-node=\"99\">ENNOTE_TOKEN\u003C\u002Fcode> environment variable.\u003C\u002Fp>\n\u003Ch3 data-path-to-node=\"5\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fh3>\n\u003Cdiv class=\"code-block ng-tns-c753567032-174 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation\">\u003C!---->\n\u003Cdiv class=\"formatted-code-block-internal-container ng-tns-c753567032-174\">\n\u003Cdiv class=\"animated-opacity ng-tns-c753567032-174\">\u003C!---->\n\u003Cpre class=\"ng-tns-c753567032-174\">\u003Ccode class=\"code-container formatted ng-tns-c753567032-174\" role=\"text\" data-test-id=\"code-content\">\u003Cspan class=\"hljs-comment\"># Example: Secure headless execution in GitHub Actions\u003C\u002Fspan>\n\u003Cspan class=\"hljs-attr\">steps:\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-bullet\">-\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">name:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">Run\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">Production\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">Migrations\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-attr\">env:\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">ENNOTE_TOKEN:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">${{\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">secrets.ENNOTE_USER_TOKEN\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">}}\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">ENNOTE_ORGANIZATION_ID:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">org_production\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">ENNOTE_WORKSPACE_ID:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">wrk_database\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-attr\">run:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">|\n      ennote secret get \"db-credentials\" -- npm run migrate\n\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!---->\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Ch3 data-path-to-node=\"5\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"10\">This entirely bypasses the interactive login handshake, allowing the CLI to fetch and inject secrets directly into the memory space of your deployment scripts.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"10\">&nbsp;\u003C\u002Fp>\n\u003Ch3 data-path-to-node=\"12\">Security by Design: The 30-Day Hard Limit\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"13\">Long-lived credentials are one of the most pervasive vulnerabilities in modern infrastructure. A token that never expires is a ticking time bomb. If a PAT is accidentally leaked in a build log or committed to version control, an attacker has perpetual access.\u003C\u002Fp>\n\u003Cp id=\"p-rc_9301a8bdc172ea32-50\" data-path-to-node=\"14\">\u003Cspan data-path-to-node=\"14,0\">To enforce security best practices, tokens must have a definitive lifespan\u003C\u002Fspan>\u003Cspan data-path-to-node=\"14,1\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003Csup class=\"superscript\">\u003C!---->\u003C\u002Fsup>\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fspan>\u003Cspan data-path-to-node=\"14,2\">. When creating a token, you can select an expiration period of 1 hour, 8 hours, 1 day, 7 days, 14 days, or a maximum of 30 days\u003C\u002Fspan>\u003Cspan data-path-to-node=\"14,3\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003Csup class=\"superscript\">\u003C!---->\u003C\u002Fsup>\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fspan>\u003Cspan data-path-to-node=\"14,4\">.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp data-path-to-node=\"14\">&nbsp;\u003C\u002Fp>\n\u003Cp data-path-to-node=\"15\">\u003Cstrong data-path-to-node=\"15\" data-index-in-node=\"0\">Why cap it at 30 days?\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Col start=\"1\" data-path-to-node=\"16\">\n\u003Cli>\n\u003Cp data-path-to-node=\"16,0,0\">\u003Cstrong data-path-to-node=\"16,0,0\" data-index-in-node=\"0\">Minimizing Blast Radius:\u003C\u002Fstrong> By enforcing a strict 30-day maximum, we ensure that the utility of a leaked token degrades rapidly.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp data-path-to-node=\"16,1,0\">\u003Cstrong data-path-to-node=\"16,1,0\" data-index-in-node=\"0\">Forcing Credential Hygiene:\u003C\u002Fstrong> Indefinite tokens encourage \"set it and forget it\" anti-patterns. A 30-day limit forces infrastructure teams to build automated rotation into their CI\u002FCD lifecycle, ensuring that credentials are treated as ephemeral artifacts rather than static infrastructure.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp data-path-to-node=\"16,2,0\">\u003Cstrong data-path-to-node=\"16,2,0\" data-index-in-node=\"0\">Compliance by Default:\u003C\u002Fstrong> SOC 2 and ISO 27001 compliance frameworks mandate strict credential rotation policies. Ennote enforces this out of the box, ensuring your pipelines remain compliant without manual oversight.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch3 data-path-to-node=\"18\">Token Management and Revocation\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"19\">We have built the PAT management UI with strict visibility and control boundaries:\u003C\u002Fp>\n\u003Cul data-path-to-node=\"20\">\n\u003Cli>\n\u003Cp id=\"p-rc_9301a8bdc172ea32-51\" data-path-to-node=\"20,0,0\">\u003Cspan data-path-to-node=\"20,0,0,0\">\u003Cstrong data-path-to-node=\"20,0,0,0\" data-index-in-node=\"0\">Token Limits:\u003C\u002Fstrong> Users can generate and manage up to 10 active Personal Access Tokens at any given time\u003C\u002Fspan>\u003Cspan data-path-to-node=\"20,0,0,1\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003Csup class=\"superscript\">\u003C!---->\u003C\u002Fsup>\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fspan>\u003Cspan data-path-to-node=\"20,0,0,2\">. This prevents token sprawl and ensures developers are actively managing their machine identities.\u003C\u002Fspan> \u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp data-path-to-node=\"20,1,0\">\u003Cstrong data-path-to-node=\"20,1,0\" data-index-in-node=\"0\">Write-Once Visibility:\u003C\u002Fstrong> For cryptographic safety, the token value is only displayed once upon creation. We do not store the plaintext token in our database; we only store a salted, one-way hash.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp id=\"p-rc_9301a8bdc172ea32-52\" data-path-to-node=\"20,2,0\">\u003Cspan data-path-to-node=\"20,2,0,0\">\u003Cstrong data-path-to-node=\"20,2,0,0\" data-index-in-node=\"0\">Instant Revocation:\u003C\u002Fstrong> Tokens can be revoked immediately from the dashboard at any time if they are no longer needed or if you suspect a compromise\u003C\u002Fspan>\u003Cspan data-path-to-node=\"20,2,0,1\">\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003Csup class=\"superscript\">\u003C!---->\u003C\u002Fsup>\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C!---->\u003C\u002Fspan>\u003Cspan data-path-to-node=\"20,2,0,2\">. Revocation instantly terminates all downstream API and CLI access utilizing that token\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 data-path-to-node=\"24\">Stay Tuned: Tokenless OIDC Integration\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"25\">While PATs provide a highly secure, time-bound bridge for standard CI\u002FCD workflows, the ultimate goal in enterprise secret management is eliminating long-lived credentials entirely.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"26\">In our upcoming releases, we plan to implement \u003Cstrong data-path-to-node=\"26\" data-index-in-node=\"47\">tokenless OIDC (OpenID Connect) integration\u003C\u002Fstrong> with major CI\u002FCD platforms (such as GitHub Actions and GitLab CI). This architectural upgrade will allow your runners to authenticate directly with Ennote using short-lived identity federation.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"27\">The result? Zero hardcoded tokens, zero rotation overhead, and an airtight, fully ephemeral security posture.\u003C\u002Fp>\n\u003Cp>&nbsp;\u003C\u002Fp>\n\u003Cdiv class=\"container\">\n\u003Cdiv id=\"model-response-message-contentr_b44085c6b6fab0da\" class=\"markdown markdown-main-panel stronger enable-updated-hr-color\" dir=\"ltr\" aria-live=\"polite\" aria-busy=\"false\">\n\u003Ch3 data-path-to-node=\"22\">Next Steps\u003C\u002Fh3>\n\u003Cp data-path-to-node=\"23\">Personal Access Tokens are available today. To configure your first token and integrate it into your automated workflows, navigate to \u003Cstrong data-path-to-node=\"23\" data-index-in-node=\"134\">User Settings &gt; Security &gt; Personal Access Tokens\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"24\">For detailed implementation instructions and security guidelines, review the \u003Ca href=\"https:\u002F\u002Fdocs.ennote.io\u002Fdocs\u002Fauth\u002Fuser-tokens\">official documentation\u003C\u002Fa> on our portal.\u003C\u002Fp>\n\u003Cp data-path-to-node=\"24\">&nbsp;\u003C\u002Fp>\n\u003Cp data-path-to-node=\"24\">&nbsp;\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C!---->\u003C\u002Fdiv>",[9,10,11,12,13,14],"EnnoteCLI","DevSecOps","SecretManagement","CICD","OIDC","DeveloperTools","https:\u002F\u002Ffirebasestorage.googleapis.com\u002Fv0\u002Fb\u002Fblog-01-c712e.firebasestorage.app\u002Fo\u002Fblog-covers%2F1781755649960_pat.png?alt=media&token=f562ecc1-bd57-4a6a-ad05-4dda32b8d853",1781755651771,"Ennote PATs: Secure Headless CI\u002FCD Automation","Automate secret injection in CI\u002FCD pipelines using Ennote Personal Access Tokens with a strict 30-day limit. Read our latest engineering update.",[20,25,30],{"title":21,"slug":22,"coverImage":23,"createdAt":24},"The Evolution of Kubernetes Secret Delivery (And Why Polling is Dead)","the-evolution-of-kubernetes-secret-delivery-and-why-polling-is-dead","https:\u002F\u002Ffirebasestorage.googleapis.com\u002Fv0\u002Fb\u002Fblog-01-c712e.firebasestorage.app\u002Fo\u002Fblog-covers%2F1777523487463_diagramm%20(2).jpg?alt=media&token=5b01f974-cfe5-4890-b68f-5e178b422c6e",1777523490608,{"title":26,"slug":27,"coverImage":28,"createdAt":29},"The Identity-Driven Cryptography Behind Ennote's Zero-Persistence Vault","the-identity-driven-cryptography-behind-ennote-s-zero-persistence-vault","https:\u002F\u002Ffirebasestorage.googleapis.com\u002Fv0\u002Fb\u002Fblog-01-c712e.firebasestorage.app\u002Fo\u002Fblog-covers%2F1778396426354_og-image.png?alt=media&token=4bd31d6a-d525-443b-8879-5178a80b5335",1778396428194,{"title":31,"slug":32,"coverImage":33,"createdAt":34},"Announcing the Ennote Certified Partner Network: Eliminate the Overhead of Legacy Infrastructure","certified-partner-network-launch","https:\u002F\u002Ffirebasestorage.googleapis.com\u002Fv0\u002Fb\u002Fblog-01-c712e.firebasestorage.app\u002Fo\u002Fblog-covers%2F1780035988445_wmremove-transformed%20(5)%20(2).png?alt=media&token=fdd2726b-b636-4356-b22d-a40eaf67949d",1780035990138,1781755886948]