Administration

Authentication

Authentication

docu.nexus supports local accounts, LDAP or Active Directory, and OAuth. They coexist. The Members list tags each person LOCAL, LDAP, or OAUTH.

Local accounts

Passwords must be at least 8 characters and are hashed with argon2id. There are no complexity, rotation, or reuse rules.

Self-registration is off by default. Turn it on under Admin, then Authentication, on the Sign-in methods tab, with Let anyone create their own account.

ALLOW_REGISTRATION on the server pins the answer instead. Setting it at all hands the decision to the deployment and the admin panel then shows registration read-only; only the exact string true enables the sign-up form. Leave it unset to manage registration from the admin panel.

Let people reset a forgotten password by email is off by default, on the same tab. When it is on, the sign-in page offers Forgot your password?, which mails a one-time link to the address on the account. It can only be switched on while email and password sign-in is on and the instance sends email (Admin, then Email). Whatever is typed, the sign-in page answers with the same sentence, so it cannot be used to find out which addresses have accounts, and nothing about the account changes until the link is used. Accounts that sign in through LDAP or SSO with no password here are never sent one. Requests are limited per address typed, per account, and per client address.

Users change their own password under My preferences, then Security, which signs out every other session on the account. Two-factor authentication is TOTP based with backup codes, and each user enables it for themselves. You cannot force it on from the admin side. See Your Account Settings.

LDAP and Active Directory

Directory sign-in is set up under Admin, then Authentication, on the LDAP tab. A directory connection belongs to the instance, not to any nexus, so only an instance administrator sees that tab; somebody who administers a nexus but not the instance does not see it at all. The step by step guide, with worked examples and troubleshooting, is LDAP and Active Directory Setup.

The client does simple bind over plain LDAP, LDAPS, or StartTLS. It does not do SASL DIGEST-MD5, GSSAPI/Kerberos, or LDAP Channel Binding.

Two switches

Directory sign-in happens when both of these are on:

  • LDAP / Active Directory on the Sign-in methods tab, for the whole instance. Switching it off keeps every connection, and switching it back on brings them back unchanged.
  • Use for sign-in on a connection, on its row in the list and on its form. A new connection is saved with it on. Off keeps the connection saved and still lets you sync it.

With more than one connection used for sign-in, each is tried in the order they were added until one accepts the password.

The LDAP_* environment variables do not configure or enable any of this. They fill in the form for a new connection, and nothing else. See Configuration for the variable names.

The list

The LDAP tab is one list of connections. Each row shows the name, host and port, the transport, a status from the same check Test connection runs, Grants instance administrator on the connection whose groups may make somebody an instance administrator, how many accounts the connection owns, and its Use for sign-in switch. Click a row to open its form; Add connection opens a blank one.

The form

The fields an operator always sets are at the top. Everything else has a working default and sits behind Advanced.

FieldNotes
NameRequired. How the connection is told apart in the list, and the label of the sign-in page’s tab while it is the only connection used for sign-in.
TransportLDAPS (636), StartTLS (389) or None. One choice, so LDAPS and StartTLS can never be asked for together.
Host and PortWhere the directory is. An empty port means the transport’s usual one. The address it will connect to is shown underneath.
Bind DNThe service account used to look people up. Leave empty, and remove any stored password, for an anonymous bind.
Bind passwordStored in the database in plaintext. Once saved it is shown only as Stored, with Replace to type a new one and Remove to clear it on the next save.
Search base DNRequired. The subtree people are looked up in.

A save that sets a new bind password checks it first. It is refused when the Bind DN is empty, when it is the password you sign in to docu.nexus with, and when the directory says it is wrong. It is stored with a warning when the directory says the account itself is locked, expired or disabled, or cannot be reached. A save that changes the address, switches StartTLS or verification off, or changes the CA, without a new password, is refused: the stored password only goes to the connection it was saved for. See Saving a bind password.

Advanced: certificate verification

For LDAPS and StartTLS only.

FieldNotes
TLS CA certificatePaste a PEM to trust an internal CA. Leave blank to use the system trust store. Once saved it is shown as Stored, with whose it is, who issued it and when it expires, and Replace and Remove.
Verify the directory’s certificateOn by default. Turning it off accepts any certificate, so treat it as a temporary diagnostic.
FieldDefault
Search filterThe built-in default below, which follows the attribute mapping.
Search scopeSubtree (default), One level, or Base
Active Directory bind domainEmpty. When set, people are bound as username@domain instead of by the DN the search found.

The built-in default filter matches either a username or an email address:

(|(uid={{username}})(mail={{username}}))

Left alone, it is rebuilt from the attribute mapping, so Active Directory usually wants the username attribute set to sAMAccountName rather than a changed filter. A changed filter is used exactly as typed; see the search filter.

Advanced: attribute mapping

A nested disclosure inside Advanced. The defaults suit OpenLDAP; Active Directory sites usually change the username attribute to sAMAccountName and the display name attribute to displayName.

FieldDefault
Username attributeuid
Email attributemail
Display name attributecn
Group membership attributememberOf
First name attributegivenName
Last name attributesn

Advanced: provisioning

  • Create an account on first successful sign-in (on by default).
  • Refresh name, email and groups from the directory on every sign-in (on by default).
  • Adopt local accounts (off by default): lets the directory take over an existing account that somebody signs into with a password. For a migration only.

There is no role and no nexus on this form. A directory places nobody into a nexus: a person’s first sign-in gives them an account and their private nexus, and an admin places them like anybody else. See Placing directory people.

Testing, syncing and deleting

Test connection runs one check with the values on the form, saved or not: it binds, then runs the sign-in search with any username and counts who it finds. Only Connected is green; a bind that finds nobody is amber. A stored password or CA you have not replaced is used as stored, and the password only against the address it was saved for. The result stays until you change a field. The status on each row in the list is the same check, run on the saved values.

Sync users now creates or refreshes an account for everybody the filter finds, switches off the accounts the connection owns that the directory no longer lists, and switches back on the ones it lists again. It places nobody into a nexus. It works whether or not the connection is used for sign-in, but it is refused while directory sign-in is off on Sign-in methods.

Delete connection asks first, naming who stops signing in and how many accounts it owns. To pause a connection without losing it, switch off its Use for sign-in instead.

You cannot take away the last way in with the change you are making. If email and password sign-in is switched off and this directory is what everyone signs in with, then deleting the connection, and switching off its Use for sign-in, are both refused with That would leave no way to sign in to this instance, and nothing is changed. The same refusal guards the switches on Sign-in methods. Enable another method first.

What that refusal cannot check is whether a configured method still works. A connection used for sign-in counts as a way in whether or not anything answers at the other end, so a directory that is unreachable, or one that is unplugged the week after you switched local sign-in off, will leave nobody able to sign in and nothing will have been refused. That is recoverable from the server: see Nobody can sign in.

OAuth and SSO

GitLab sign-in is set up by an instance administrator in Admin, then Authentication, on the Single sign-on tab. Microsoft is still configured with environment variables on the server.

GitLab

  1. In GitLab, create an application under Applications in your user settings, a group’s settings or the Admin area. Paste the panel’s Redirect URL into the application’s redirect URI (the Copy button copies it exactly), and tick the scopes the panel lists under Requested scopes.
  2. In the panel, enter the GitLab URL (leave it empty for gitlab.com), the Application ID and the Secret from the application’s page, and press Save.
  3. Press Test. It checks that the GitLab answers this server and accepts the Application ID and secret, and signs nobody in. Only a real sign-in proves the redirect URL and the scopes.
  4. Switch on Offer GitLab on the sign-in page. It saves on its own.

Once saved, the secret is never shown again: Replace types a new one, and Clear removes it when you save. Button label is what the sign-in page shows after “Sign in with”.

Under Who may sign in:

  • Create an account on first sign-in: when off, somebody with no account here is turned away until an administrator creates their account and links their GitLab user to it (see Linking GitLab to an existing account).
  • Allowed groups: GitLab group paths as they appear in the group’s URL, separated by commas. A member of any one of them may sign in.
  • Allowed email domains: matched exactly, so example.com does not let in eng.example.com.

Empty lists let everybody in. Both lists are checked on every sign-in, not only the first. A new account joins no nexus either way: an admin of each nexus adds people there.

The GitLab URL cannot change while anybody signs in through it, because GitLab’s user ids only mean the same person on the GitLab that issued them. Unlink those people first on their pages under People & Access, then link their users at the new GitLab. Changing it also needs the new GitLab’s secret.

Linking GitLab to an existing account

The first time somebody signs in with GitLab, and an account here already has their address, the two are linked only when both of these hold:

  • GitLab says the address is verified, and
  • they type that account’s own password once on the page that follows: its directory password for an account that signs in through LDAP, and the code from their authenticator app as well when the account has one.

After that, signing in with GitLab goes straight in. Five wrong tries end the attempt, and they sign in with GitLab again to start over; ten in an hour close it for that account until the hour is out. Those limits hold however many tries arrive at once.

The account’s holder is told every time this happens: a message in their Notifications channel, and an email when this instance sends email, naming the GitLab, the GitLab user and the time. Each person sees what can sign in as them under My profile in the user menu, on the Security tab, in Sign-in identities, and can unlink any of them there, which also signs out every other device. Changing or resetting a password, or an administrator issuing a new credential, unlinks the GitLab sign-ins that were confirmed with the old password, so a stolen password does not leave a GitLab way in behind it. A sign-in confirmed with a directory password is not affected by a directory password change, because docu.nexus never sees one; unlink it by hand.

Everybody else is told on the sign-in page to ask an administrator: an address GitLab has not verified, an account with no password of its own (one an administrator created without one, or one that only ever signed in through another provider), an instance administrator’s account, and anybody whose link was made through a different GitLab. Each link remembers the GitLab it was made through, and a sign-in through any other is refused.

A first sign-in that would create a new account is refused too when GitLab has not verified the address, and the person is told to confirm it at GitLab and sign in again, so nobody can take an address by typing it into their GitLab profile. A linked account’s placeholder address (from the group sync or a directory with no mail) is replaced by the GitLab address only once GitLab has verified it.

An instance administrator links and unlinks people by hand on the person’s page under Admin, then People & Access, in Sign-in identities. It lists each linked identity with the GitLab it was linked through, the GitLab user and when it was linked. To link one, type the person’s GitLab user id, the number GitLab shows on their profile page, and press the plus button. docu.nexus first asks GitLab who that user is, and the confirmation names their username, name and profile page, so a mistyped number shows a stranger rather than linking one; a user GitLab does not know, or does not call active, is refused. Asking GitLab uses the administrator’s own GitLab sign-in, so an administrator who has never signed in with GitLab does that once first (or the instance’s OAUTH_GITLAB_SYNC_TOKEN is used while sign-in goes to the GitLab OAUTH_GITLAB_URL names). A GitLab user already linked to somebody else is refused, and so is a second GitLab user at the same GitLab on one person. The minus button on a row unlinks it and ends that person’s sessions at once, so a wrong link stops working straight away. Both ask before they change anything, and both are recorded in the audit log with the administrator who did it. An administrator cannot unlink the only way their own account signs in.

The access a GitLab sign-in gives lasts two hours. docu.nexus renews a person’s GitLab sign-in before Kanban uses it, and when GitLab will not renew it the board asks them to sign in with GitLab again.

An instance first set up with the OAUTH_GITLAB_CLIENT_ID, OAUTH_GITLAB_CLIENT_SECRET, OAUTH_GITLAB_URL and OAUTH_GITLAB_SYNC_GROUP_ID variables has them copied into the panel once, the first time it starts with the panel empty, so sign-in keeps working. From then on the panel is what sign-in uses, a restart applies none of the variables, and the panel names any that differ from it.

GitLab group sync sits below the panel. Enter a Sync group (the group’s numeric id or its full path) and save, then Sync from GitLab creates an account for every member of that group, and keeps the role of everybody already linked to their GitLab user. It never links a member to an account that already exists here: the address a group member shows is whatever they last typed into their GitLab profile, so a matching account is reported by name in the run’s results instead, with the two ways to link it (the person signs in with GitLab once and confirms with their password, or an administrator links them on their page). The next run then syncs them as usual. Only an instance administrator can run it.

Microsoft

Variables
OAUTH_MICROSOFT_CLIENT_ID, OAUTH_MICROSOFT_CLIENT_SECRET, OAUTH_MICROSOFT_TENANT_ID (defaults to common)

Register the callback URL with Microsoft as <APP_URL>/api/auth/oauth/microsoft/callback, and restart the server after changing the variables. Microsoft appears on the sign-in page once both its client id and secret are set.