Skip to content
ShadowMC

Configuration

ShadowLogin

The door of your server, and everyone who walks through it.

Premium v1.0.4

Where the files are

plugins/ShadowLogin/

The plugin creates them on first start and updates them by itself on new versions, keeping your changes.

Applying changes

/shadowlogin reload

Reloads the files without restarting the server.

What’s inside

4 files · 117 settings

Start with: config.yml

Settings

The files that decide how the plugin behaves. Start here.

config.yml

General settings
111 settings
plugins/ShadowLogin/config.yml
File notes

Every value here already holds the right number for an ordinary server: you can drop in the jar and never open this file. When you do need to change something, the comment above each key says WHAT it does and, more importantly, WHY it is set that way.

A wrong value never stops the plugin: the default is used instead and the console prints the path and what was expected.

On update your files are moved to the new version automatically: every value you changed is carried over, new options arrive with their comments, the old files are kept in backup/<date>/, and if something needs your attention you will find PORTING-<version>.txt in the plugin folder.

Durations are written in plain text: 500ms, 20t (ticks), 30s, 5m, 2h30m, 7d. A bare number means seconds.

This file is English on purpose - keys, sections and comments alike - so that a server anywhere in the world reads the same configuration. Only what a player sees is translated, and that lives in lang/.

config-version6

Licence

ShadowLogin is a Premium plugin: there is no free edition. Without a valid licence at start-up it does NOT run - no database, no login, nothing but the licence commands below - and says so in the console. Activate the licence, then restart the server.

Keep reading

While it is not running, a server that does not verify players itself (offline mode, with no online-mode proxy forwarding to it) REFUSES EVERY CONNECTION: without its login plugin anybody could join under any name, an operator's included. In online mode, or behind an online-mode proxy, players join normally.

A licence that stops applying while the server is running never stops the plugin mid-session: that would lock everybody out or let everybody in. The session carries on, and the console says ShadowLogin will not start at the next restart.

You normally touch nothing here: a key is activated in game with

/shadowlogin license claim <purchase-code>
/shadowlogin license activate <key>

and is written to license.yml, which sits outside this file on purpose: a config gets sent to support, a licence does not.

license4 keys

THE KEY LIVES IN license.yml (same folder as this file), or in the central plugins/ShadowControl/licenses.yml for the whole suite. The 'key' below is only a fallback for deploy systems that generate config.yml: leave it empty.

The key does NOT live here: it lives in license.yml, in this folder, written at first start (or in plugins/ShadowControl/licenses.yml for the whole suite). Only if you would rather keep it here than in license.yml. The SHADOWLOGIN_LICENSE environment variable and the -Dshadowlogin.license=... system property work too.

grace-days7

Days of grace, running normally, before the licence stops applying when a subscription expires or when the server address does not match the licence. A renewal has almost always already been started, and an address that stops matching is far more often a NAT than a thief.

server-ip""

The address this server is known by, if you know it. Behind a proxy the machine never sees its own domain, and this line is the only way to tell it without calling anybody.

resolve-public-iptrue

One call at start-up to the licence service (activation-url + /ip) to find out this server's public address: behind NAT it is the only way to recognise it. Only when a licence is installed: a server without a key asks nobody. false = never ask.

activation-url'https://shadow-licences.riccardobotins.workers.dev'

Activation service. This is the BASE address: the plugin appends /claim and /check itself. Empty means fully offline verification.

Security

The part you do not change lightly. The defaults are right for ninety per cent of servers; every time you lower one you are trading security for convenience, and the comment tells you what it costs.

security7 keys
security.hash2 keys
cost12

BCrypt's cost factor. Every +1 DOUBLES the time it takes.

Keep reading
10 -> about 60 ms      a little thin in 2026
12 -> about 250 ms     the recommended value
14 -> about 1 second   for few players and a lot of worry

The time is paid by whoever logs in (once) and by whoever attacks (for every single attempt, multiplied by millions). That is the whole reason SHA-256 is not used here: it is fast, and "fast" is exactly the gift you do not want to hand somebody who steals a database.

CAREFUL on a server with hundreds of connections a minute: hashing runs off the game thread, so it never costs you ticks, but it does hold a thread for as long as it runs. Above 13 on a very busy server, measure.

rehash-on-logintrue

When you raise the cost above, existing accounts still carry the old hash. With this option each password is recomputed at the new cost on its owner's next login: nobody has to do anything, and within a few days the whole database is up to date.

It never works the other way round: if you lower the cost, stronger hashes are left alone.

security.password5 keys
min-length6

Minimum length. Six is the honest compromise for a Minecraft server: below that it gets guessed, above it people write it on a sticky note or reuse one from another site.

max-length64

The maximum is NOT strictness: BCrypt only looks at the first 72 bytes, so beyond that characters stop counting. The plugin says so rather than letting you find out the day you change the end of a very long phrase and the old one still works.

require-letter-and-digitfalse

Require a letter AND a digit. Off by default, and that is not an oversight: complicated rules produce worse passwords ("Marco1", "Password1") and stop nobody. If you turn it on, know what you bought.

forbid-name-as-passwordtrue

Forbid a password identical to the player's own name. This one yes, because it is the first thing anybody tries.

forbidden
[password, 123456, 12345678, qwerty, minecraft, abc123, 111111, letmein, iloveyou]+6

Passwords that may not be used. These are the first entries in any dictionary: blocking them costs nothing and removes half of the account thefts on a Minecraft server.

Add your own server name: it is always on an attacker's list.

security.attempts7 keys
max5

How many attempts before being kicked. Five is generous for somebody who really did mistype and tight for somebody guessing.

window"10m"

How long before a mistake is forgotten. Somebody who got it wrong once last month should not be dragging it around.

backoff-base"5s"

The wait after the first mistake, which then DOUBLES with every further one: 5s, 10s, 20s, 40s... up to the ceiling below.

Keep reading

This is the defence that actually matters. A hard limit of five attempts is worked around by waiting for the reset; a doubling wait turns a dictionary from three attempts a second into three an hour, which is an attack that never finishes.

Attempts are counted per ADDRESS and per NAME, both. Counting only the name lets through somebody trying "123456" on a thousand different names; counting only the address lets through a botnet on one account.

backoff-max"10m"
lock-after10

After how many mistakes the account is locked outright, and for how long.

lock-duration"30m"
kick-on-maxtrue

Whether to kick somebody who has run out of attempts. On: whoever is guessing passwords has to reconnect every time, and reconnecting goes through the antibot limits.

security
login-timeout"60s"

How long there is to log in before being kicked. Mostly this is against people who open connections and leave them sitting on a slot.

reminder-every"5s"

How often to remind somebody waiting what they are supposed to do. Five seconds is enough to be noticed without becoming annoying.

clear-chat-after-authtrue

After logging in, push what was typed off the screen.

HONESTLY: no plugin can clear the client's local history - the up arrow will still bring back the typed command, and that is a limit of the game, not an oversight. This takes the line out of sight immediately, so it is not left sitting there while somebody watches the screen.

If this genuinely worries you, the answer is login.input: GUI: with the on-screen keypad the password never goes through the chat box at all.

clear-chat-lines30

Official accounts (Mojang / Microsoft)

The feature this plugin exists for. Read at least the first two paragraphs before changing anything below.

Keep reading

THE RIGHT QUESTION. It is not "does this name belong to a bought account?" - that says nothing about who is knocking right now, and letting anybody who types an official name in without a password would be handing over every bought account on the server. The right question is: "has this session ALREADY been authenticated by Mojang?"

Which can be answered with facts, without touching a single packet:

1. the server is in online-mode -> yes, the server did it;
2. the session's UUID is Mojang's real one for that name -> then it comes
   from upstream, that is from the proxy that authenticated the person,
   because a client cannot choose it for itself.

CASE 2 DEPENDS ON HOW YOUR NETWORK IS SET UP. If identity forwarding from the proxy is not protected (server port open to the world, or the old BungeeCord forwarding without a shared secret), anybody can connect directly and declare whatever UUID they like. That is not a flaw in this plugin and no plugin can repair it from the inside: it is a server that can be walked around. Set trust-proxy-authentication: false if you are not sure about your network.

premium9 keys
enabledtrue

Turns the whole chapter off: no calls to Mojang, passwords for everybody.

modeAUTO
AUTO = an already-authenticated session comes in without a password.
OFF  = nobody skips the password, but name protection stays on.
Keep reading

On AUTO this is FOR LIFE and has no expiry: an official account is re-verified by Mojang on every single connection, so there is nothing to remember and nothing that can run out. Those players never see the login screen again - not after a restart, not after a month, not from a new computer. It works as long as one of these two is true:

- the server is in online-mode, or
- the server sits behind a proxy with forwarding configured, and
  trust-proxy-authentication below is on.

On a plain offline-mode server with no proxy in front there is no way to verify anybody, and everyone types a password. That is not a limit of this plugin: it is what offline-mode means.

trust-proxy-authenticationtrue

Whether to trust the UUID arriving from a proxy. Read the paragraph above: if you leave this on, make sure your server can ONLY be reached through the proxy. It only ever applies when this server really has proxy forwarding on (paper-global.yml proxies.velocity.enabled, or spigot.yml settings.bungeecord) and that proxy is declared online-mode (proxies.velocity.online-mode / proxies.bungee-cord.online-mode). Without forwarding no UUID comes from a proxy, and none is trusted.

force-passwordfalse

Ask for a password even from somebody Mojang already authenticated. For people who want two barriers instead of one: it is less convenient and it is more secure, and it is a legitimate choice for a server with expensive ranks.

protect-namestrue

Stop a name belonging to a real account from being registered by an unauthenticated session.

This is the most important protection in the whole chapter. Without it anybody can connect using an official player's name before the owner arrives, register it with a password of their own, and from that moment they are that player: it is the most common theft on mixed servers.

lookup-timeout"3s"

How long to wait for Mojang's answer. Three seconds is generous: it sits in the middle of a connection, and one extra second is felt by whoever is coming in.

cache-hours72

How many hours to remember an answer. A bought name stays bought; a free name bought today is discovered within three days at worst. Raising it reduces calls, lowering it increases them.

on-lookup-failureCACHE_THEN_PASSWORD

What to do when Mojang does not answer (it happens: they have had outages lasting hours). Under no circumstance is anybody blocked from coming in.

CACHE_THEN_PASSWORD = use the last known answer, otherwise ask for the
                      password (recommended)
PASSWORD            = just ask for the password
api-url"https://api.mojang.com/users/profiles/minecraft/"

The service address. Change it only if you use a mirror.

Identity - read this chapter in full

On a server that also accepts unofficial accounts, THE SAME NAME CAN ARRIVE WITH TWO DIFFERENT UUIDS. Somebody who bought the game brings Mojang's UUID with them; somebody who did not gets one computed from the name, and the two never coincide.

Keep reading

Minecraft keeps inventory, progress, position and everything else PER UUID. Getting this setting wrong means handing one player's inventory to another. This is not a textbook case: it is exactly what happens to somebody who one day puts a proxy in front of their server.

UUID (default)

One account per UUID. The official "Marco" and the unofficial "Marco" are
two separate accounts, with two passwords and two inventories - which is
also what the server is going to do anyway, so the plugin is not telling
a different story from the true one. On its own it is not enough: it is
premium.protect-names that stops the second of the two from being born.

NAME

One account per name, like AuthMe and like almost every existing server.
The UUID seen at registration is still stored, and if another one turns
up one day with the same name, on-uuid-mismatch below applies.

If you are importing from AuthMe, NAME is what you expect. If you are starting from scratch, leave UUID.

identity3 keys
modeUUID

One person, one identity - read this if your server is mixed

identity
unify-uuid"OFF"

THE PROBLEM, with the example that actually happens. Marco logs in with the original game, gets Mojang's UUID, and builds an island. The next day he logs in from an unofficial client with the same name: that UUID is a different one, so to the server he is A DIFFERENT PERSON. New island, empty inventory, no money. Marco does not understand, and he is right not to: he is still Marco.

Keep reading

The important thing to understand is that this is not a login problem. The island, the inventory, the money and the permissions are kept by OTHER plugins, and every one of them keys on the UUID. So it is not enough for this plugin to keep its own house in order - the whole server has to see one single UUID. That is what this setting does, and it is the only place where ShadowLogin changes something that is not its own.

OFF      = change nothing (default). Official and unofficial stay two
           different people, with two accounts, two islands and two
           inventories - which is also what the server would do by
           itself. Right for a server where the two never mix.
OFFLINE  = everybody gets the UUID computed from the name, official
           players included. RECOMMENDED on a mixed server, and the
           reason is that it depends on nobody: that UUID is worked
           out from the name with a calculation, always the same,
           without asking any service anything. A UUID that changes
           because Mojang was down for five minutes is a lost island.
PREMIUM  = everybody gets Mojang's real UUID, when the name has one.
           For servers that already have data created in online-mode
           and do not want to lose it. It costs one dependency: if
           Mojang does not answer for a name never seen before, the
           plugin does NOT guess - it refuses the connection with
           "try again in a minute". Letting somebody in under the
           wrong UUID is not an inconvenience like retyping a
           password: it is landing on nobody's island and building
           on it.

CAREFUL if the server already has data. Turning this on means people get a new UUID, and everything saved under the old one stays where it is and stops being reachable. On a new server there is nothing to worry about. The console says so loudly at start-up.

AND ONE THING THAT GOES WITH IT: with the UUIDs unified, an account born from an official login still has no password, and without a password there is no way in from an unofficial client. That is on purpose - it is what stops a stranger from claiming the name. The owner logs in with the original game once and sets a password with /changepassword; from then on both clients open the same account, with the same island. The plugin tells them so by itself the first time.

Quoted on purpose. In YAML, OFF and ON are not words: they are booleans. The plugin understands both spellings either way - it translates a boolean back into the word you wrote - but quoting says what you meant, and keeps the file readable by anything else that parses it.

on-uuid-mismatchDENY

What to do when the name is right but the UUID is not.

DENY         = refuse the connection and write it in the console
               (recommended: this is exactly the dangerous case)
ASK_PASSWORD = let them try with the password, with no shortcuts at all
               (useful while you are changing your network setup and you
               know what you are doing)
ALLOW        = adopt the new UUID as the account's own
               (only for a migration, and only for as long as it takes)

Session

Somebody reconnecting from the same address within N minutes does not retype their password. This is the feature that decides whether your login plugin is loved or hated: without it, anybody on a flaky connection types their password ten times an evening.

session3 keys
enabledtrue
duration"30m"

How long it lasts. Half an hour covers a disconnect, a server restart and a hop between servers on a network; several hours starts to be a real window for somebody sitting down at another person's computer.

require-same-iptrue

Tie the session to the address. Leave this on: without it a session would be valid from anywhere in the world, and at that point the password would be needed exactly once, ever.

Keep reading

CAREFUL - and this is the real limit of any address-bound session: if two people share the same public address (the same house, the same school, or a mobile network, where thousands of users come out of one address) then inside the session window one of them can come in under the other's name without typing anything.

That is not a flaw in this plugin: it is what "same address" means. If your server has a lot of players on mobile networks, the defence is to shorten the duration above (five minutes still covers a disconnect) or to turn sessions off entirely with enabled: false.

Trusted device ("remember me") [Premium]

WHO THIS IS FOR. Not for players with an official Minecraft account: those never type a password in the first place, because Mojang says who they are on every single connection, for life. Offering them a token would add one more key that can be stolen, for a door that is already open without a key - so the plugin does not offer it to them at all.

Keep reading

This is for the OTHER players, the ones without an official account. For them a password is the only proof there is, and typing it every evening is the reason people go and play somewhere else. With this, they type it once on a computer and then not again for a week.

HOW IT WORKS, in one line: after a password login the server hands the client 32 random bytes (a "token") and keeps only its SHA-256 fingerprint in the database. On the next connection the client presents it, the fingerprint matches, and no password is asked.

WHY IT IS NOT A HOLE - and this is the part worth reading:

1. The token is REPLACED on every use. Each login issues a new one and

the old one stops opening anything. Trust is renewed at every use, so
the week counts from the last time you came in, not from the first.

2. The old one is REMEMBERED for a moment (see rotation-grace). If it

turns up again after that moment, then two copies of it exist in the
world - and the second one was not made by the owner. That is a
theft, and the plugin treats it as one: trust is revoked on EVERY
device of that account at once, so the thief loses even the access
they already had, and the owner finds out immediately because the
password is asked again.

3. Only a password issues one. Not a resumed session, not an official

login, not a staff-forced entry. Somebody sitting down at another
person's computer while they are logged in takes nothing away.

4. Trust dies when something changes: password changed, password reset

by staff, recovery code issued, /logout, account deleted.

5. The token is never in the database, only its fingerprint. A database

dump lets nobody in, exactly as with passwords.

6. It is not the password: it cannot change it, cannot read it, and does

not skip two-factor.

This is the same scheme serious systems use for refresh tokens. It does not make stealing a token from a computer you have your hands on impossible - nothing does - but it makes that theft worth exactly one login, and impossible to hide.

WHAT THE TOKEN CANNOT DO, AND WHAT IS DONE ABOUT IT. Minecraft keeps cookies in the game's MEMORY, not on disk: close the game and the token is gone. On some setups it never even arrives - an older proxy, a client that does not answer in time, a server with accepts-transfers turned off. The practical result of relying on the token alone is a "remember me" that hardly ever remembers, which is worse than not having one: people click it and get the password screen anyway.

So a remembered device is anchored to a second thing that survives all of that: the ADDRESS it was switched on from. See "anchor" below. That is a weaker proof - somebody who shares your address, in the same house or behind the same carrier, looks exactly like you - and it is a choice you make knowingly. But it is a proof that is always there, while the other one often is not.

The two live together: when the token arrives it wins, and that is better. When it does not, the address carries it, and the feature keeps doing what the player expects.

IF YOU HAVE A PROXY (Velocity, BungeeCord, Waterfall): the cookie belongs to the connection between the client and the address it connected to, which is the proxy. So every server behind the same proxy sees the same cookie.

- Shared database (MySQL/MariaDB): the best case. Trust a device once
  and it holds across the whole network.
- Separate databases: one server's token matches no row on the other
  and is ignored. Nobody sneaks in, nobody is locked out.
- Want the servers not to even see each other's cookie? Give each one a
  different cookie-name below.
trusted-device10 keys
enabledtrue
automaticfalse

Automatic, or on request.

false = a [ REMEMBER ME ] button appears after login and the player
        decides (recommended: trust is given, not imposed)
true  = a token is issued by itself on every password login
duration"7d"

How long a token is worth, counted from the last time it was used - so a player who comes back every evening never meets the login screen, and a computer somebody stopped using stops being trusted a week later.

anchorADDRESS

What a remembered device is anchored to when the client does not hand the token back. This is the setting that decides whether the feature actually works on your server.

Keep reading
ADDRESS = token first; if it does not arrive, the address the device was
          switched on from is accepted instead. RECOMMENDED, and the
          default: it survives closing the game and restarting the
          server, which is what a player means by "remember me".
          The trade: anybody sharing that address is indistinguishable
          from the owner for as long as the trust lasts. On a home
          connection that is the family; behind a mobile carrier it can
          be thousands of people. Shorten "duration" if that worries you.
COOKIE  = the token and nothing else. Stronger, and much more fragile:
          closing the game means typing the password again, and on some
          setups it means typing it every single time.

If you want the token path to work as often as possible, set accepts-transfers=true in server.properties: cookies belong to the same family of packets, and some clients will not answer without it.

rotation-grace"2m"

How long the just-replaced token is still accepted.

It exists for one real case: the connection drops between the moment the server replaces the token and the moment the client receives the new one. Inside this window the old one still works; outside it, presenting it means two copies exist, and the second was not made by the owner.

Keep it short. Every second here is a second in which a stolen copy would still be accepted as an honest retry.

require-same-ipfalse

Tie a remembered device to the address it was issued from.

Off by default, and on purpose: the whole point of this feature is to NOT depend on the address, which changes on its own (mobile data, a router reboot) and is shared by everybody in the same house. Turn it on only if your players have stable addresses and you want a second lock.

max-per-account3

How many different computers one account may remember. The oldest drops off when number N+1 arrives.

skips-two-factorfalse

Whether a trusted device also skips two-factor authentication.

Leave this false: the token proves the computer is the usual one, not that the right person is sitting in front of it. Those are two different questions, and somebody who turned on a second factor asked for both.

read-timeout"1500ms"

How long to wait for the client's answer DURING the connection. This is the fast path, and it holds a network thread while it waits, so it stays short on purpose.

Keep reading

It is not the only path: if no answer arrives in time, the plugin asks again once the player is in the world, where nothing is being held up and there is no hurry. That second question is what makes "remember me" work on slow clients, older proxies and versions that do not know cookies - you do not have to configure anything for it.

Two-factor authentication

Optional, and switched on by whoever wants it, on their own account. It is for the few accounts that are worth something: staff, people who bought ranks, people with a base full of things. Forcing it on everybody gets it disabled by players in the simplest way available: by going to play somewhere else.

two-factor4 keys
enabledtrue
issuer"ShadowLogin"

The name shown in the authenticator app. Put your server's name here: somebody with twenty entries in their app needs to work out which one is you.

window1

How many codes to accept before and after the current one (one = a minute and a half in total). This is for clocks that are not in sync. Raising it multiplies the codes valid at any instant: if you need more than 1, the problem is the server's clock.

backup-codes8

How many backup codes to hand out. They are for the day the phone breaks: without them, that day the account is lost.

Recovery

recovery2 keys
recovery.question1 key
enabledtrue

The security question, set by the player.

recovery.staff-code2 keys
length8

The code an operator generates with /shadowlogin resetpassword. This is the honest route: an administrator recognises the person and hands them a temporary token, instead of walking into the account in their place.

valid-for"15m"

Limbo - where somebody sits before they have logged in

An empty sky and a message. Somebody who has not typed their password sees nothing and does nothing: no chat, no commands other than the login ones, no movement beyond a radius, no inventory, no real position. Everything you let them see is information given away to somebody trying to get into another person's account.

limbo8 keys
enabledtrue
use-spawntrue

Use the player's world spawn, raised to the height below. Turn it off to use the fixed position in location.

limbo.location6 keys
world""
x0.5
y320

Three hundred and twenty blocks: there is nothing to look at above the clouds, and from up there you cannot even tell which part of the map you are on.

z0.5
yaw0
pitch0
limbo
radius3

How many blocks one may move. Not zero: blocking movement entirely makes the client "rubber-band" and the screen shakes. Three blocks let client and server stay in agreement.

hide-playerstrue

Hide those waiting from everybody else, and everybody else from them. That way the login screen cannot be used to spy on who is online.

blindnesstrue

Blindness: the empty sky mentioned above.

hide-inventorytrue

Put the inventory aside and give it back after login.

The snapshot is written to the database BEFORE emptying anything, and if that write fails the inventory is not touched at all. So a sudden server crash costs nobody anything: on the first login after the restart everything comes back where it was.

freeze-hungertrue

No hunger while waiting.

Antibot

A bot attack does not try passwords: it opens connections. Three hundred fake clients a second, each with an invented name, each taking a slot and a database row. The server does not fall over from gameplay load: it falls over because every connection costs a read and a write.

antibot7 keys
enabledtrue
max-connections-per-ip3

How many simultaneous connections from one address. Three lets a family with three brothers through and stops a botnet on a single address.

IF YOU ARE BEHIND A PROXY WITHOUT REAL-ADDRESS FORWARDING, this number applies to THE WHOLE SERVER AT ONCE: read the "proxy" chapter below. The plugin notices by itself and tells you in the console.

max-registrations-per-ip2

How many registrations from one address inside the window. This is the limit that matters most: creating accounts is the only thing a bot can do that REMAINS after it has gone.

registrations-window"24h"
antibot.join-rate2 keys
connections8

Above this many connections inside the window, the plugin works out that something is happening. Eight in five seconds is far more than a normal server sees, even a full one.

window"5s"
antibot.adaptive3 keys
enabledtrue

Strict mode switches itself ON above the threshold above, and for a few minutes only people who already have an account get in.

Keep reading

This is the defence worth more than all the others put together, because a bot wave is one hundred per cent made of names never seen before - and your players do not even notice it happening.

It switches itself on because an attack arrives at four in the morning, and a switch you have to flip by hand gets flipped twenty minutes later.

(Part of the Premium edition. The fixed thresholds above apply to everybody, licence or not.)

duration"5m"
block-registrationstrue

During strict mode, block new registrations as well.

antibot
name-pattern"^[A-Za-z0-9_]{3,16}$"

The shape a name has to have. The default is exactly what Minecraft allows: 3 to 16 letters, digits and underscores.

CAREFUL if you have Bedrock players through Geyser: their names carry a prefix (usually a dot) and are longer. In that case use:

"^[.A-Za-z0-9_ ]{3,20}$"

Proxy - read this if you have a BungeeCord or a Velocity in front

Behind a proxy, the address the server sees is the PROXY's, not the player's. Without forwarding configured, all your players look like they are connected from the same address, and therefore:

- the antibot's per-address limits block real players;
- per-address sessions become one single session for everybody.
Keep reading

The fix is NOT in this file: it is in the proxy.

Velocity   -> modern forwarding, plus paper-global.yml with
              proxies.velocity.enabled: true and the right secret
BungeeCord -> ip_forward: true, and the server reachable ONLY from the
              proxy (firewall!), because that forwarding is not
              authenticated

The plugin checks by itself whether many different names are arriving from one address and, if so, tells you in the console once.

proxy1 key
use-forwarded-addresstrue

Use the address the proxy declares (the player's real one). Set it to false only if you do NOT trust your forwarding: in that case everybody will look like they come from the same address. With forwarding on and this set to false the plugin knows it, and switches off everything keyed on the address: the per-address limits (they would apply to the whole server), address-bound sessions and devices remembered by address (they would let in anybody typing the name).

How people log in

login3 keys
inputBOTH
CHAT = /login and /register only
GUI  = the on-screen keypad only
BOTH = both, and the player chooses
Keep reading

The keypad exists because a command typed in chat is readable by anybody looking at the screen, and a plugin cannot clear the client's history. With the GUI you click and dots appear.

A PIN is weaker than a long password and there is no point pretending otherwise: six digits is a million combinations. It holds up because attempts are counted and slowed down - at the tenth mistake the account is frozen for half an hour, and a million attempts at that rate is centuries.

login.gui3 keys
open-on-joinfalse

Open the keypad by itself on join. Off by default: somebody used to typing /login would get a window in their face.

pin-length6

How many digits the PIN has. Do not go below six.

click-delay"120ms"

Minimum wait between two clicks, against click bots.

login
hide-join-message-until-logintrue

Do not announce "Marco joined" before Marco has typed his password: whoever joined is somebody who typed the name Marco. The message is sent after login, and if the login never happens it is not sent at all.

Storage

storage5 keys
table-prefix"sl_"

The table prefix. Change it if two servers share one database but must NOT share accounts.

storage.mysql7 keys
enabledfalse

An external MySQL or MariaDB. It buys one thing, and it is worth it only for that: on a network, a registration made on one server counts on all the others.

(Part of the Premium edition. Without a licence the plugin stays on the local database, with all of its data, and says so in the console.)

host"127.0.0.1"
port3306
database"shadowlogin"
username"root"
password""
parameters"useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&characterEncoding=utf8"
storage
fallback-to-localtrue

If MySQL does not answer, start on the local database instead of not starting. On: a login plugin that does not start is a closed server.

storage.h21 key
auto-serverfalse

Lets another process open the same H2 file. Only useful if you know why you need it.

storage.pool5 keys
maximum-pool-size10
minimum-idle2
connection-timeout-ms10000
idle-timeout-ms600000
max-lifetime-ms1800000

Messages

messages3 keys
default-locale"en_US"

The default language. The files live in lang/: the plugin ships en_US and it_IT, and a file you add there is picked up too.

follow-client-localetrue

Follow the language each player has set in their client.

auto-updatetrue

Move the language files to the new version when the plugin is updated: new texts arrive, the texts you changed stay yours, and the previous file is kept in backup/<date>/. With false the files in lang/ are never rewritten, and a text missing from them is read from the copy inside the jar.

compatibility1 key
section-color-codestrue

Accept the section character as well as & in colour codes.

Integrations

(all optional, all switched off by themselves if the other piece is missing)

integrations4 keys
refuse-other-login-pluginstrue

Do not start if another login plugin is installed.

Two plugins handling entry do not add up: they get in each other's way, and the result is not "more secure" but UNDEFINED. Leave this on.

integrations.shadowcontrol2 keys
reportstrue

Suspicious registrations and repeated attempts become a report in the panel. No password and no secret ever ends up in there: only what happened and to whom.

report-seconds60
integrations.shadowessentials1 key
spawn-after-logintrue

Teleport to spawn after login, and not before: before would mean showing spawn to somebody who has not yet proved they are who they say.

integrations.shadowpermissions1 key
hold-until-logintrue

Permissions are recomputed after login. Before that none of them apply, and not because we take them away: because there is nothing that could use them.

Diagnostics

logging2 keys
console-attemptstrue

Write every wrong password to the console (name and address, never the password). Useful for noticing a targeted attack.

log-sqlfalse

Write every SQL statement. Only for working out a problem: it is slow and it fills the log.

metrics1 key
enabledtrue

bStats (https://bStats.org): how many servers use this plugin and which version they are on. What is sent, every 30 minutes: a random server id (serverUuid, not derived from anything), the plugin version, the Minecraft/Paper and Java versions, the operating system and core count, the online mode, how many players are online (a number only) and the licence tier (free/premium/creator). No player data of any kind: no names, no UUIDs, no addresses, no passwords. Nothing is sent while the plugin waits for a licence.

Keep reading

false switches off this plugin only. enabled: false in plugins/bStats/config.yml switches off every bStats plugin at once.

Languages

The texts the plugin shows to players, one file per language.

lang/

Texts and messages
2 files
plugins/ShadowLogin/lang/
File notes

This file holds the TEXT. Everything else in the plugin - keys, sections, comments, commands - is English on purpose, so that a server anywhere in the world reads the same configuration. Only what a player sees is translated, and this is where it lives.

Every message the plugin shows to players, one file per language. The keys are not listed one by one: here are the files, how many texts they hold and the placeholders they use.

FileLanguageTexts
lang/en_US.yml reference English 303
lang/it_IT.yml Italiano 303

Most used placeholders

The plugin replaces them with the right value: leave them written as they are.

  • <prefix>
  • <label>
  • <name>
  • <value>
  • <count>
  • <time>
  • <mode>
  • <max>
  • <ip>
  • <duration>
  • <file>
  • <date>
  • <reason>
  • <min>

Message groups

  • prefix 1
  • common 13
  • command 4
  • login 34
  • register 5
  • password 13
  • device 19
  • twofactor 23
  • recovery 7
  • limbo 4
  • antibot 5
  • gui 14
  • admin 117
  • license 38
  • locked 6

All the documentation