Back to Message Handlers (.z Namespace)

Interprocess Communication (IPC) · Message Handlers (.z Namespace) · Practice Question

Implement .z.pw to Authenticate Connecting Users

Sign in to track your progress

Question

Which .z handler is used to authenticate a connecting user, what arguments does it take, and how would you implement it?

Solution

/ Allow all connections unconditionally
.z.pw:{[username;password] 1b}
/ Deny all connections
.z.pw:{[username;password] 0b}
/ Allow only specific users
.z.pw:{[username;password]
  username in `jeremy`alice`bob
 }
/ Check both username and password
users:`jeremy`alice!("secret123";"pass456")

.z.pw:{[username;password]
  $[username in key users; password~users username; 0b]
 }

The username arrives as a symbol and the password as a string.

Explanation

.z.pw takes two arguments — the username and password supplied by the connecting client — and must return a boolean:

  • Return 1b — connection is allowed; .z.po fires next and the connection is established.
  • Return 0b — connection is rejected; the client receives a 'access error.

The client supplies credentials by embedding them in the connection string:

h:hopen `:localhost:5001:jeremy:secret123

Without a custom .z.pw, q accepts any incoming connection with no credential check. The handler runs before .z.po, so a connection that fails .z.pw never reaches .z.po at all.

.z.pw can use any logic — a hardcoded list, a lookup against a table populated from a file, or a call to an external authentication service. Whatever approach is used, the return value is the only thing that matters to q: 1b opens the connection, 0b denies it.

A typical pattern for file-based credentials is to load a user table at startup and check against it inside .z.pw. Storing a hash of each password rather than the password itself is safer; this example uses q's built-in md5:

/ users.csv has a header row and columns username,pwhash (an md5 hex string)
users:("S*";enlist",") 0: `:users.csv

.z.pw:{[u;p]
  h:exec pwhash from users where username=u;
  $[count h; (first h)~raze string md5 p; 0b]
 }

(md5 is used here only to keep the example short; it is not a strong password hash.)