This page covers the security-related features of Jarvis: encrypting the connection with TLS, authenticating requests, and validating them before your endpoint code runs.
By default Jarvis serves plain HTTP. To serve HTTPS (TLS), set Secure to 1 and tell Jarvis where to find the server's certificate and private key:
- Certificate and key files: set
ServerCertFileto the public certificate file andServerKeyFileto the private key file. - Windows certificate store: alternatively, on Windows, set
ServerCertSKIto the certificate's Subject Key Identifier and Jarvis will load it from the Microsoft Certificate Store. - Root certificates:
RootCertDirnames a folder of root CA certificates. On Windows, leaving it empty uses the operating system's certificate store.
j←Jarvis.New ''
j.Secure←1
j.ServerCertFile←'/path/to/server-cert.pem'
j.ServerKeyFile←'/path/to/server-key.pem'
j.StartSSLValidation controls how Jarvis treats client certificates. The default, 64, requests a client certificate but does not require one; when a client presents one, it is available to your code as req.PeerCert. See Priority for the cipher/protocol settings passed to Conga.
TLS underpins the other features here: HTTP Basic credentials and session tokens are only as safe as the connection carrying them, so run a service that authenticates its users over HTTPS.
Authentication decides who may call your service. Jarvis runs an authentication hook for each request, before your endpoint code: set AuthenticateFn to the name of a function in CodeLocation. The function is passed the Request instance and returns:
0— the request is authenticated, or no authentication is required, so processing continues;- non-
0— authentication failed; Jarvis fails the request with HTTP status401(Unauthorized).
If the function signals an error, Jarvis fails the request with 500.
Your function can base its decision on whatever the request carries — the UserID and Password from HTTP Basic authentication (below), a bearer token or API key in a header, a cookie, or session state.
∇ r←Authenticate req
⍝ AuthenticateFn: allow a request only if it carries a known API key
r←~(⊂req.GetHeader'x-api-key')∊KnownKeys
∇If no AuthenticateFn is defined, every request is allowed (subject to validation and, for WebSockets, WsAuthenticateFn). WebSocket connections authenticate separately; see Using WebSockets.
HTTP Basic authentication is the scheme in which the client sends a user name and password in the Authorization header. It is controlled by HTTPAuthentication, which defaults to 'basic'; set it to '' to disable Basic authentication.
Jarvis handles two parts of the scheme for you:
- Decoding credentials. When a request carries an
Authorization: Basic …header, Jarvis decodes it and setsreq.UserIDandreq.Password, ready for yourAuthenticateFnto check. - Challenging the client. When
HTTPAuthenticationis'basic'and yourAuthenticateFnrejects a request (returns non-0), Jarvis adds aWWW-Authenticate: Basicheader to the401response, which prompts a browser to ask the user for credentials.
Jarvis does not decide whether the credentials are valid — that is your AuthenticateFn's job:
∇ r←Authenticate req
⍝ AuthenticateFn: check the Basic-auth user name and password
r←~(req.UserID req.Password)≡'admin' 'secret'
∇Basic authentication sends the user name and password only Base64-encoded, not encrypted, so always use it over TLS.
Validation decides whether a request is acceptable — its shape, headers, size, content-type and so on — independently of who sent it. Set ValidateRequestFn to the name of a function in CodeLocation. It is called for every request, is passed the Request instance, and returns:
0— the request is acceptable, so processing continues;- non-
0— the request is rejected; Jarvis fails it with HTTP status400(Bad Request).
ValidateRequestFn runs before AuthenticateFn, so use it for checks that don't depend on identity — for example rejecting an unexpected content-type or an over-large body:
∇ r←Validate req
⍝ ValidateRequestFn: require JSON requests no larger than 1 MB
r←(~'application/json'≡req.ContentType)∨(1e6<≢req.Body)
∇The hook can also adjust the request's response before failing it — for example to set a custom status or an explanatory payload.