Skip to main content
Version: v3

Authentication

Authentication is split into two modules:

  • Member Provider - handles authentication and authorization of users, can be used to authenticate users against a database, LDAP, or any other system.

    NOTE

    LDAP, OIDC, and other subsystems are not currently implemented. If you are interested in these features, please consider contributing or sponsoring their development.

  • Session Provider - handles session management, after the module authenticates the user, it creates a session and handles the session lifecycle.

Member Profile​

A member profile is a structure that describes the user and what the user is allowed to do in the system.

FieldDescriptionType
nameUser's name as shown in the UI, must not be unique within the system (not used as an identifier).string
avatarAvatar URL shown in clients that support member avatars. OAuth logins synchronize this value from the configured user-info field.string
is_adminWhether the user can perform administrative tasks that include managing users, sessions, and settings.boolean
can_loginWhether the user can log in to the system and use the HTTP API.boolean
can_connectWhether the user can connect to the room using the WebSocket API (needs can_login to be enabled).boolean
can_watchWhether the user can connect to the WebRTC stream and watch the room's audio and video (needs can_connect to be enabled).boolean
can_hostWhether the user can grab control of the room and control the mouse and keyboard.boolean
can_share_mediaWhether the user can share their webcam and microphone with the room.boolean
can_access_clipboardWhether the user can read and write to the room's clipboard.boolean
sends_inactive_cursorWhether the user sends the cursor position even when the user is not hosting the room, this is used to show the cursor of the user to other users.boolean
can_see_inactive_cursorsWhether the user can see the cursor of other users even when they are not hosting the room.boolean
pluginsA map of plugin names and their configuration, plugins can use this to store user-specific settings, see the Plugins Configuration for more information.object
Example member profile in YAML
name: User Name
avatar: https://example.com/avatar.png
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true
plugins:
<key>: <value>

Member Providers​

Member providers are responsible for deciding whether given credentials are valid or not. This validation can either be done against a local database or an external system.

info

Currently, Neko supports configuring only one authentication provider at a time. This means you must choose a single provider that best fits your deployment needs.

Multi-User Provider​

This is the default provider that works exactly like the authentication used to work in v2 of neko.

This provider allows you to define two types of users: regular users and admins. Which user is an admin is determined by the password they provide when logging in. If the password is correct, the user is an admin; otherwise, they are a regular user. Based on those profiles, the users are generated on demand when they log in and they are removed when they log out. Their username is prefixed with 5 random characters to avoid conflicts when multiple users share the same username.

Profiles for regular users and admins are optional, if not provided, the default profiles are used (see below in the example configuration).

member:
provider: "multiuser"
multiuser:
# Password for admins, in plain text. (string)
admin_password: "admin"
# Profile fields as described above (object)
admin_profile: {}
# Password for regular users, in plain text. (string)
user_password: "neko"
# Profile fields as described above (object)
user_profile: {}
See example configuration

The default profiles for regular users and admins are as follows, highlighting the differences between them.

config.yaml
member:
provider: multiuser
multiuser:
admin_password: "admin"
admin_profile:
name: "" # if empty, the login username is used
is_admin: true
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true
user_password: "neko"
user_profile:
name: "" # if empty, the login username is used
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: false
tip

For easier configuration, you can specify only passwords using environment variables:

docker-compose.yaml
environment:
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "admin"
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "neko"

OAuth 2.0 Provider​

Neko can use an OAuth 2.0 authorization-code provider. It exchanges the authorization code server-side and fetches the configured user-info endpoint. Provider access tokens, refresh tokens, and raw ID tokens are never persisted or returned to the browser.

For OpenID Connect providers, set issuer_url. Neko retrieves /.well-known/openid-configuration from that issuer and uses its authorization, token, and user-info endpoints. Issuer discovery takes precedence over explicitly configured endpoints, so it can be introduced without removing older endpoint settings.

When redirect_url is omitted, Neko derives the callback URL from the browser request as https://<neko-host>/api/oauth/callback (including server.path_prefix). Register that exact URL with the provider. Behind a TLS-terminating reverse proxy, set server.proxy: true so Neko trusts X-Forwarded-Proto and X-Forwarded-Host. The user-info endpoint must return JSON. success_redirect is relative to server.path_prefix.

config.yaml
member:
provider: "oauth"
oauth:
enabled: true
# When true, visiting the Neko root page immediately starts OAuth login.
auto_redirect: true
name: "Example SSO"
admin_emails: ["platform-admin@example.com", "security@example.com"]
user_emails: [] # if empty, any authenticated user is allowed to log in
client_id: "<client-id>"
client_secret: "<client-secret>"
issuer_url: "https://id.example.com"
scopes: ["openid", "profile", "email"]
# Configure these to match the JSON returned by userinfo_url.
subject_field: "sub"
username_field: "name"
avatar_field: "picture"
success_redirect: "/"
user_profile:
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: false
admin_profile:
is_admin: true
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true

The sign-in endpoint is GET /api/oauth/login; the callback endpoint is GET /api/oauth/callback. OAuth login requires session.cookie.enabled: true, which is the default. Set member.provider: oauth to make OAuth the only member provider.

admin_emails is a list matched against the standard email field, case-insensitively. An OAuth user is an administrator when either their email matches that list or their user-info/ID-token claims include isAdmin: true; their permissions then use admin_profile. The configured name and avatar fields are read from userinfo first, then fall back to the ID token when userinfo omits them. Avatar URLs are rendered by clients that support member avatars.

user_emails restricts non-admin login to a list of allowed emails, matched the same way as admin_emails. If user_emails is empty (the default), any authenticated user is allowed to log in. Administrators (matched by admin_emails or isAdmin: true) can always log in regardless of user_emails. Users whose email is not allowed receive an HTTP 403 response and no session is created.

warning

admin_emails and user_emails are matched against the email claim. Most providers only include that claim if the email scope is requested, so scopes must include "email" (in addition to "openid") or the claim will be empty and these lists will never match.

For OAuth sessions, GET /api/whoami includes extra_data: the merged userinfo and ID-token claims, with userinfo values taking precedence. It is returned only to the authenticated session owner and is intended for profile-field troubleshooting. Do not place secrets in provider profile claims.

For non-OIDC providers, set authorization_url, token_url, userinfo_url, and optionally redirect_url directly. For GitHub, for example, use read:user as a scope and set subject_field: id, username_field: login, and avatar_field: avatar_url.

File Provider​

This provider reads the user's credentials from a file. It is useful for small deployments where you don't want to set up a database or LDAP server and still want to have persistent users.

member:
provider: "file"
file:
# Absolute path to the file containing the users and their passwords. (string)
path: "/opt/neko/members.json"
# Whether the passwords are hashed using sha256 or not. (boolean)
hash: false

It allows you to store the user's credentials in a JSON file. The JSON structure maps user logins to their passwords and profiles.

members.json
{
"<user_login>": {
"password": "<user_password>",
"profile": /* Member Profile, as described above */
}
}

You can leave the file empty and add users later using the HTTP API.

See example members.json file

We have two users, admin and user with their passwords and profiles. admin is a regular user, while user is an admin.

Please note that the passwords are stored in plain text. To store them securely, set the hash field to true in the configuration. After that, the passwords are expected to be hashed using sha256 and base64-encoded. The file will look like this:

members.json
{
"admin": {
"password": "admin",
"profile": {
"name": "Administrator",
"is_admin": true,
"can_login": true,
"can_connect": true,
"can_watch": true,
"can_host": true,
"can_share_media": true,
"can_access_clipboard": true,
"sends_inactive_cursor": true,
"can_see_inactive_cursors": true,
"plugins": {}
}
},
"user": {
"password": "neko",
"profile": {
"name": "User",
"is_admin": false,
"can_login": true,
"can_connect": true,
"can_watch": true,
"can_host": true,
"can_share_media": true,
"can_access_clipboard": true,
"sends_inactive_cursor": true,
"can_see_inactive_cursors": false,
"plugins": {}
}
}
}

If you want to hash the passwords, you can use the following command to generate a sha256 base64-encoded hash of the password:

echo -n "password" | openssl sha256 -binary | base64 -

Object Provider​

This provider is the same as the file provider, but it saves the users only in memory. That means that the users are lost when the server is restarted. However, the default users can be set in the configuration file. The difference from the multi-user provider is that the users are not generated on demand and we define exactly which users with their passwords and profiles are allowed to log in. They cannot be logged in twice with the same username.

member:
provider: "object"
object:
# List of users with their passwords and profiles. (array)
users: []
See example configuration

We have two users, admin and user with their passwords and profiles. admin is an admin, while user is a regular user.

config.yaml
member:
provider: object
object:
users:
- username: "admin"
password: "admin"
profile:
name: "Administrator"
is_admin: true
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true
- username: "user"
password: "neko"
profile:
name: "User"
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: false

No-Auth Provider​

This provider allows any user to log in without any authentication. It is useful for testing and development purposes.

member:
provider: "noauth"
danger

Do not use this provider in production environments unless you know exactly what you are doing. It allows anyone to log in and control neko as an admin.

Session Provider​

Currently, there are only two providers available for sessions: memory and file.

Simply by specifying the session.file to a file path, the session provider will store the sessions in a file. Otherwise, the sessions are stored in memory and are lost when the server is restarted.

session:
file: "/opt/neko/sessions.json"
info

In the future, we plan to add more session providers, such as Redis, PostgreSQL, etc. So the Configuration Options may change.

API User​

The API User is a special user that is used to authenticate the HTTP API requests. It cannot connect to the room, but it can perform administrative tasks. The API User does not have a password but only a token that is used to authenticate the requests. If the token is not set, the API User is disabled.

session:
api_token: "<secret_token>"
tip

This user is useful in some situations when the rooms are generated by the server and the token is guaranteed to be random every time a short-lived room is run. It is not a good idea to define this token for long-lived rooms, as it can be stolen and used to perform administrative tasks.

You can generate a random token using the following command:

openssl rand -hex 32

Cookies​

The authentication between the client and the server can be done using cookies or the Authorization header. The cookies are used by default, but you can disable them by setting the enabled to false.

warning

If you disable the cookies, the token will be sent to the client in the login response and saved in local storage. This is less secure than using cookies, as the token can be stolen using XSS attacks. Therefore, it is recommended to use cookies.

session:
cookie:
enabled: false
name: "NEKO_SESSION"
expiration: "24h0m0s"
secure: true
http_only: true
domain: <string>
path: <string>
info

The secure and http_only are set to true by default, which means that the cookie is only sent over HTTPS. If you are using HTTP, you should really consider using HTTPS. Only for testing and development purposes should you consider setting it to false.