# What is CFA?

{% hint style="danger" %}
**In light of** [**planned changes to npm token management**](https://github.blog/changelog/2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management/) **announced by GitHub, the Electron team has decided to deprecate the Continuous Factor Authentication project.**

**We recommend migrating your projects to** [**Trusted publishing for npm packages**](https://docs.npmjs.com/trusted-publishers)**.**
{% endhint %}

CFA stands for Continuous Factor Authentication.  Its core goal is to enable the usage of two-factor authentication (2FA) for automated package publishing to improve the security of the Node.js ecosystem.

At Electron, we've been using [semantic-release](https://github.com/semantic-release/semantic-release) to automate the release of various `@electron/` packages on npm. However, [semantic-release requires you to use npm's `auth-only` 2FA level](https://semantic-release.gitbook.io/semantic-release/usage/ci-configuration#authentication-for-plugins), meaning package publishing cannot behind two-factor authentication.

CFA solves this problem by providing a secure means to deliver a 2FA token to CI builds while keeping 2FA turned on for write operations such as `npm publish`.

### How does it work?

In a typical [2FA model](https://en.wikipedia.org/wiki/Multi-factor_authentication), there is **"something you know"** and **"something you have".** For [npm 2FA](https://docs.npmjs.com/configuring-two-factor-authentication), which relies on time-based one-time passwords (TOTPs):

* You **know** your npm auth token
* You **have** the TOTP generator

At a high level, CFA is just a proxy for the existing 2FA process. It safely mediates a connection between a given CI build and you by validating the CI build through both a CFA token and by forcing the CI build to "prove" it is actually asking for a token.

If you want to understand how the "prove it" part of that flow works, there is a [Flow Diagram](https://github.com/continuousauth/web/blob/main/docs/proof-process.png) in the CFA repository that explains how it works.

### Is it completely automated?

CFA is 99% automated. The final step of giving a CI build a 2FA token requires human interaction **by design**. CFA never wants to know your 2FA secret—that should be something you keep control of and protect as much as you can.  When CFA is happy with a CI build, we will use whichever [Responder](/usage/responders) you configured to ask you (the human) for a Tting OTP.

###


# Projects

In order to use CFA for one of your repositories you have to add it as a "project" in CFA.  You can do this with the "Add Project" button in the top right of the [dashboard](https://continuousauth.dev).  In order to add your repository to CFA you need have **admin** access to the repository on GitHub.  If you don't have this access you should reach out to someone who does

Once you have added a project to CFA you should be able to configure whichever [Requester](/usage/requesters) and [Responder](/usage/responders) you want to use.  Check out those documentation pages for more information on what those are and how they work.

### Audit Log

For each project you set up in CFA there will be a log of each incoming OTP request, whether it was responded to, and who responded to it each time along with appropriate timestamps for each event.  In the unfortunate scenario where your CI environment is compromised this will help you quickly determine if you gave the compromised environment an OTP at any point.

### Renaming a project

If you rename your repository on GitHub it is *possible* that CFA could get confused about incoming requests.  We recommend that once you rename your repository on GitHub you head over to CFA and use the "Add Project" button to re-add the repository to CFA.  This will simply cause the existing project to be aware of the new repository name, your existing configuration will not be affected.

### Deleting a project

If you delete a project all information related to that is deleted and the project is marked as "de-activated" meaning all incoming OTP requests will be rejected.  If you ever want to re-add that project you can do so but you will need to set up your Requester and Responder configuration again.


# Requesters

In CFA when we refer to a `Requester` we are referring to the part of your build process that would be running `npm publish` this is typically a CI provider such as Circle CI, Travis or Azure Pipelines.  It is the service that will actually be "requesting" the OTP from CFA.

Once you added your repository as a project in CFA you should be able to choose from any of our supported Requesters to configure.  For more information on each Requester, what they validate and how to configure them please check the individual Requester pages.

### I want to use CI provider X but there is not a requester for it?

Check out our [Contributing FAQ](/contributing/faq#i-want-to-use-cfa-with-ci-provider-x) for more information on how to add a new requester.  We're always open to new pull requests.


# CircleCI

{% hint style="info" %}
This Requester is fully implemented and requires no extra instructions, follow the setup instructions on the project page on CFA itself to get it working
{% endhint %}

{% hint style="warning" %}
The CircleCI Requester works via the legacy logs based proof process, this will be migrated to OIDC at some point in the future.
{% endhint %}


# GitHub Actions

{% hint style="success" %}
The GitHub Actions requester uses OIDC for everything, setting up the project in the web UI will automatically configure a protected environment on GitHub containing required secrets.
{% endhint %}


# Travis CI

{% hint style="info" %}
Documentation for this Requester hasn't been written yet, following the setup instructions on the project page on CFA itself should help you get it working though.
{% endhint %}


# Responders

In CFA when we refer to a `Responder` we are referring to the part of the CFA process that interacts with the human to ask for an OTP, this is typically a chat integration like Slack.  It is the service that will actually be "responding" to the OTP request.

Once you added your repository as a project in CFA you should be able to choose from any of our supported Responders to configure.  For more information on each Responder and how to configure them please check the individual Responder pages.


# Slack

{% hint style="info" %}
Documentation for this Responder hasn't been written yet, following the setup instructions on the project page on CFA itself should help you get it working though.
{% endhint %}


# Semantic Release

Once you have added your [Project](/usage/projects) to CFA and set up a [Requester](/usage/requesters) and a [Responder](/usage/responders) for that project you can go ahead and configure Semantic Release to use CFA.

### Step 1: Configure your CI environment

In order for CFA to run and authenticate correctly you must configure the following environment variables on your CI provider.

| Environment Variable | Value                                                         |
| -------------------- | ------------------------------------------------------------- |
| `CFA_SECRET`         | The "Project Secret" found on your Project configuration page |
| `CFA_PROJECT_ID`     | The "Project ID" found on your Project configuration page     |

These variables are automatically configured by the `CircleCI`and `GitHub Actions`requesters.

### Step 2: Configure Semantic Release

You should [configure Semantic Release](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/getting-started.md#getting-started) following the default instructions.  Then once it's completely set up you should add `@continuous-auth/semantic-release-npm` as a dev-dependency to your project. You do not need to configure a `GITHUB_TOKEN`as that will be provided automatically by CFA.

{% tabs %}
{% tab title="Yarn" %}

```bash
yarn add @continuous-auth/semantic-release-npm --dev
```

{% endtab %}

{% tab title="NPM" %}

```bash
npm install @continuous-auth/semantic-release-npm --save-dev
```

{% endtab %}
{% endtabs %}

&#x20;Then add the following file to the root of your project

{% code title=".releaserc.json" %}

```javascript
{
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@continuous-auth/semantic-release-npm",
    "@semantic-release/github"
  ]
}
```

{% endcode %}

This is identical to the default configuration but with the default npm plugin swapped out for the CFA one.

### Step 3: Try trigger a release

Everything should be completely set up now, try pushing a semantic commit to master and see if it releases your module.

### Step 4 (Optional): Use GitHub Action

CFA provides a convenient, secure GitHub Action you can use to easily set up Semantic Release. You can check it out [here](https://github.com/continuousauth/action).


# Manual Usage

For advanced users you may want to tap into the CFA client directly and use it in custom deployment scripts, the set up for requesters and responders is identical to the other documentation.

When you want to consume the client you may either hit the APIs yourself, or consume the [@continuous-auth/client](https://www.npmjs.com/package/@continuous-auth/client) npm package directly.

We **strongly** reccomending using the package as it will be kept up to date with any potential changes, the APIs are also undocumented and we may break or remove certain APIs at any time without notice.


# Storing OTPs

CFA permanently stores your provided OTPs alongside the request, there is no real **technical** reason for this we could easily wipe them after the request has been obtained and at some point we might. While CFA is still in preview we keep it around for debugging purposes. To explain how this doesn't make your OTP secret less secure I'd like to refer you to the original [OTP RFC](https://tools.ietf.org/html/rfc4226#section-6).

> Assuming an adversary is able to observe numerous protocol exchanges and collect sequences of successful authentication values. This adversary, trying to build a function F to generate HOTP values based on his observations, will not have a significant advantage over a random guess.

Basically, you can have as many examples of OTPs for a given secret as you want and it won't make it any easier for an attacker to guess a valid OTP.


# Multi-User 2FA

{% hint style="warning" %}
Although this is documented the implementation has not yet shipped
{% endhint %}

When an open source project is large enough a potential use case involves having multiple developers with merge rights to master.  This combined with Semantic Release technically means multiple developers have the ability to trigger a release.  On CI there is traditionally only a single `NPM_TOKEN`, this means that either:

* The developers share a single npm account like specific for that project.  An example of this is the `electron-bot` npm user.
* Or the developers use a single developers account on CI.

The issue with the second one is that in order for other developers to be able to enter 2FA tokens into CFA they would need the 2FA secret for that single developers npm account.  This would be terrible for the security of that users account and doesn't make a whole lot of sense.

To help with this use case CFA supports the use of **multiple** npm tokens on your CI configuration and allows the user entering the 2FA token to choose which one they want to use.

### How to set this up?

Traditionally Semantic Release uses a single environment variable `NPM_TOKEN` to provide the npm access token required to publish the package.  With CFA instead of providing `NPM_TOKEN` you can provide a number of `NPM_TOKEN_{username}` variables such as `NPM_TOKEN_marshallofsound` or `NPM_TOKEN_electronbot` which CFA will read and let you choose from when asking for your 2FA token.

Please note that if you provide tokens in that format you should **not** provide the default `NPM_TOKEN` variable.

### What is the benefit of this system?

By putting multiple access tokens on CI you can let developers publish with their own access token and their own 2FA codes.  This means you don't have to share access to a single npm account or distribute your 2FA secret around all your maintainers.

### What does it look like?

*Screenshots coming soon*


# FAQ

## Is CFA Open Source?

Yes, 100%. CFA was originally built by the [Electron](https://github.com/electron/) team and is open source over at <https://github.com/continuousauth>.

## I want to use CFA with CI provider X

If we don't already support X we would totally accept a pull request adding support for that provider.  You can check out the code and go about adding a new "Requester" by following the pattern set forth by the ones already implemented.  You'll need to implement the backend logic and the front end configuration component.  Make sure you raise an issue first so that multiple people don't implement the same thing.


