Paperless-ngx: Activate Two-Factor-Authentication (2FA)
How to activate the integrated multi-factor authentication for Paperless-ngx and secure your access. An overview of all configurations for 2FA.
Last updated: Apr 25, 2025
Table of Contents

š Audio Version
Listen to this AI-generated podcast summarizing the article content for easier digestion
The web interface of Paperless-ngx only offers a login with a username and password after the default installation.
In 2025, this is not that secure. If someone finds out your password, they're in the system. Won't happen, you think? It only takes one data breach. A phishing email or a virus that records keyboard input. Or the lack of an encrypted connection over HTTP. Especially when it comes to sensitive documents, additional protection is indispensable.
Since the release of 2.5.0, Paperless-ngx supports the integration of multi-factor authentication through various providers.
Multi-factor or two-factor means that in addition to entering your password, you must confirm the login through another method. For example, by entering a TOTP code that you retrieve via email, SMS, or a smartphone app. To bypass this, an attacker would need simultaneous access to both methods, which is significantly harder.
Update January 2025: Since the release of 2.14 Paperless-ngx has built-in two-factor authentication via TOTP codes. You can simply activate it in your user profile.

Multi-factor authentication is done through an external provider. Paperless-ngx uses a Django backend and supports all Django Allauth providers. You can see a list of all providers here and choose one or more providers.
If you want to host an application for authentication yourself, the OpenID-connect (OIDC) interface is a good option. You can use OIDC with Authelia or Keycloak - two popular open-source software tools. However, the setup requires significantly more technical knowledge. If you're interested in a tutorial on this, let me know in the comments.
You can set up most third-party providers very easily. I'll show you the setup with Github here as an example, which is free. The setup with other providers is similar.
This can help you choose the right provider: Find out which providers most of your employees already have an account with.
First, you register your Paperless app with one of the providers. Then you receive a client ID and a security key (secret) from the provider.
For registration with Github, go to this page and fill out all the required fields. You can set any name for your app.
For the homepage URL, set the URL where your Paperless instance is accessible.
Finally, define the callback URL to which Github redirects after successful login. To do this, add this section to the end of your homepage URL /accounts/github/login/callback/
.

After you have submitted the form, you can generate a client secret. For the next step, you will need the client secret and the client ID.

Open the directory where you have installed Paperless-ngx and where the Docker Compose configurations are located. Open the file docker-compose.env
. I connect to my Linux server via SSH and open the file with the text editor nano:
1sudo nano docker-compose.env
At the end of the file, add two variables:
1PAPERLESS_APPS=allauth.socialaccount.providers.github2PAPERLESS_SOCIALACCOUNT_PROVIDERS={"github": {"APPS": [{"provider_id": "github","name": "Github","client_id": "<CLIENT_ID>","secret": "<CLIENT_SECRET>"}]}}
Replace the placeholders CLIENT_ID
and CLIENT_SECRET
with your keys.
Save the file and close the text editor. I do this using the commands CTRL+X
followed by Y
and ENTER
.
To save the settings, you need to restart the Docker containers. Execute the following command:
1docker compose down && docker compose up -d
After about a minute, your Paperless instance should be accessible again.
Now, if you navigate to your Paperless instance, you will see two login options: Login with GitHub and the regular login with username and password.

Log in as usual with your regular access data to your admin account. Access your profile. You will now see a button that allows you to link your account with GitHub.

Click on the button and connect your account. Log out of Paperless and your Github account and test if you can log in with Github. This should work without any problems.
For multi-factor authentication to work, you need to add it to your GitHub account. As long as your GitHub session is active, you will remain logged in to your Paperless instance.
Open the docker-compose.env file again. Add another variable to the end of the file:
PAPERLESS_DISABLE_REGULAR_LOGIN=true
Save and close the file and restart the Docker containers. When Paperless is back online, the regular login should be gone.

There are two limitations you currently have to live with if you want to use the Paperless MFA integration. Perhaps it will be patched in future updates.
There is currently a security vulnerability that ruins all our previous work. That is the Django admin panel. You can access the Django admin panel via the URL path /admin/
. https://paperless.domain.com/admin/
You can still log into the admin panel with your regular access data!


As soon as you are logged in, you can navigate to your Paperless dashboard and have access to all your documents. This means: You can bypass the multi-factor authentication, which is not what we want.
Update: since version 2.8 you can deactivate the admin panel by removing the permission in your user settings:

Alternatively, a simple solution to close the security vulnerability is to block the path /admin/
login in your web server settings. Where exactly you need to make the settings depends on the web server you are using and where it is installed on your system.
If you are using Nginx as a reverse proxy like I do, you probably have the directory /etc/nginx/sites-available
. Here is the configuration for the domain under which my Paperless instance is running.
Go to the directory:
1cd /etc/nginx/sites-available
Open the configuration:
1sudo nano paperless.domain.com
Add the following code to your server block:
1location /admin/login {2 return 302 /;3}
What does the code do? As soon as a user calls the path to the admin panel, they are redirected to the root path /
. An HTTP status code 302 (temporary redirection) is thrown.
Save and close the file and test for syntax errors with:
1sudo nginx -t
If everything is ok, restart Nginx:
1sudo systemctl restart nginx
With this, the security vulnerability is closed. You can still access the Django admin panel when you are logged in.
A new user can simply register for your app via the login page with their GitHub account. The user then appears in your account under the users' section.
Theoretically, any visitor to your login page can register. But don't worry: After registration, the user has no permissions or access to your data.
You must edit the user in the users' section and assign them permissions. If the user should not be authorized, you can simply delete them.
If you intend to deactivate the registration of new users via your login page, add the variable PAPERLESS_SOCIALACCOUNT_ALLOW_SIGNUPS=False
to your configuration and restart the docker containers.
The integration of multi-factor authentication into Paperless is an important step to make your instance more secure against attackers. The integration of Django Allauth providers is simple but comes with some limitations.
There are many more ways to secure your Paperless instance. Most of it is a general server topic and has nothing to do with the Paperless app itself. For example, you could connect a multi-factor authentication via Authelia with your reverse proxy. For every incoming request, an authentication request is sent. The response instructs the reverse proxy to either allow or block the incoming request. Paperless is only loaded after successful authentication.
Continuous Improvement
Execution-Focused Guides
Practical frameworks for process optimization: From workflow automation to predictive analytics. Learn how peer organizations achieve efficiency gains through ROI-focused tech adoption.
Explore moreComments
sfreek
Apr 27, 2025, 12:18 AM

Tobias Wupperfeld
Apr 27, 2025, 12:20 AM
Daniel
Apr 27, 2025, 12:30 AM
Daniel
Apr 27, 2025, 12:31 AM

Tobias Wupperfeld
Apr 27, 2025, 12:31 AM
Martin
Apr 27, 2025, 12:34 AM

Tobias Wupperfeld
Apr 27, 2025, 12:34 AM
Leave a comment
Your email address won't be published.