Repository: nats-io/nats-server

Issue:
Can't use Auth Token in Leaf Remote URL without Authorization error
### Observed behavior

When running a server that accepts leaf connections at any port (let's say standard 7422) and configured for auth token, and running a leaf node that has a properly formatted remote URL for that server, such as `nats-leaf://token@hub-server:7422`, both endpoints repeatedly report authorization violations errors and report the token as the user in the error indicating that it is incorrectly misconstruing the auth-model as User/Pass.

### Expected behavior

The expectation would be that Leaf node authenticate via Token would work as is documented 

### Server and client version

Hub version 2.12.x
Leaf version 2.12.x

Works in 2.11.10

### Host environment

Any OS, Any CPU, any runtime

### Steps to reproduce

Much of the configuration doesn't appear to matter as long as the accepting node is configured for leaf connections and the connecting node is using the documented Remote URL format

Discussion:
@jbudbo: I debugged the scenario locally and from what I can tell this could be fixed at this line:
https://github.com/nats-io/nats-server/blob/d897a1aedabf53423a5b7d54b5f1e7eed7de71ea/server/auth.go#L1126.

From what I can tell, simply changing to this should work
`if c.kind == CLIENT || c.kind == LEAF {`

I just don't know if there would be any other ramifications from such an edit@MauriceVanVeen: Could you share the full config you're using for both servers?@jbudbo: hey @MauriceVanVeen can do
# hub.conf
```text
leafnodes {
    port: 7422
}
authorization {
    token: "myToken"
}
```
# leaf.conf
```text
leafnodes {
    remotes = [
        {
            url: "nats-leaf://myToken@0.0.0.0:7422",
        }
    ]
}
```@MauriceVanVeen: Thanks for confirming, can reproduce this.@jbudbo: Amazing thank you!

On Tue, Oct 21, 2025 at 6:09 PM Neil ***@***.***> wrote:

> Closed #7441 <https://github.com/nats-io/nats-server/issues/7441> as
> completed via #7452 <https://github.com/nats-io/nats-server/pull/7452>.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/nats-io/nats-server/issues/7441#event-20416129046>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AGACZX34SGKVIPTSY7R3TBT3Y2VH3AVCNFSM6AAAAACJPY3TH2VHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMRQGQYTMMJSHEYDINQ>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>


Solution patch:
diff --git a/server/auth.go b/server/auth.go
index 2d735c0e..ede29744 100644
--- a/server/auth.go
+++ b/server/auth.go
@@ -1123,7 +1123,8 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) (au
 		return ok
 	}
 
-	if c.kind == CLIENT {
+	// Check for the use of simple auth.
+	if c.kind == CLIENT || c.kind == LEAF {
 		if proxyRequired = opts.ProxyRequired; proxyRequired && !trustedProxy {
 			return setProxyAuthError(ErrAuthProxyRequired)
 		}
diff --git a/server/leafnode.go b/server/leafnode.go
index 0049823d..f306ebc9 100644
--- a/server/leafnode.go
+++ b/server/leafnode.go
@@ -1049,17 +1049,22 @@ func (c *client) sendLeafConnect(clusterName string, headers bool) error {
 	// In addition, and this is to allow auth callout, set user/password or
 	// token if applicable.
 	if userInfo := c.leaf.remote.curURL.User; userInfo != nil {
-		// For backward compatibility, if only username is provided, set both
-		// Token and User, not just Token.
 		cinfo.User = userInfo.Username()
 		var ok bool
 		cinfo.Pass, ok = userInfo.Password()
+		// For backward compatibility, if only username is provided, set both
+		// Token and User, not just Token.
 		if !ok {
 			cinfo.Token = cinfo.User
 		}
 	} else if c.leaf.remote.username != _EMPTY_ {
 		cinfo.User = c.leaf.remote.username
 		cinfo.Pass = c.leaf.remote.password
+		// For backward compatibility, if only username is provided, set both
+		// Token and User, not just Token.
+		if cinfo.Pass == _EMPTY_ {
+			cinfo.Token = cinfo.User
+		}
 	}
 	b, err := json.Marshal(cinfo)
 	if err != nil {



Test patch:
diff --git a/server/leafnode_test.go b/server/leafnode_test.go
index d0ea7305..9d7f94bd 100644
--- a/server/leafnode_test.go
+++ b/server/leafnode_test.go
@@ -10830,3 +10830,37 @@ func TestLeafNodeConfigureWriteDeadline(t *testing.T) {
 		require_Equal(t, r.out.wdl, 6*time.Second)
 	})
 }
+
+// https://github.com/nats-io/nats-server/issues/7441
+func TestLeafNodesBasicTokenAuth(t *testing.T) {
+	hubConf := createConfFile(t, []byte(`
+		server_name: "HUB"
+		listen: "127.0.0.1:-1"
+		authorization {
+			token: secret
+		}
+		leafnodes {
+			listen: "127.0.0.1:-1"
+		}
+	`))
+	hub, ohub := RunServerWithConfig(hubConf)
+	defer hub.Shutdown()
+
+	port := ohub.LeafNode.Port
+	leafTmpl := `
+		server_name: "LEAF"
+		listen: "127.0.0.1:-1"
+		leafnodes {
+			remotes: [
+				{ url: "nats://secret@localhost:%d" }
+			]
+		}
+	`
+	leafConf := createConfFile(t, fmt.Appendf(nil, leafTmpl, port))
+	leaf, _ := RunServerWithConfig(leafConf)
+	defer leaf.Shutdown()
+
+	// Verify that we have only 1 leaf
+	checkLeafNodeConnected(t, hub)
+	checkLeafNodeConnected(t, leaf)
+}