node package manager

Introducing npm Enterprise add-ons. Integrate third-party dev tools into npm…


bagarino ======== &quot;bagarino&quot; <em>sells</em> you tickets and can tell a real ticket from a fake one. Simple, fast and RESTful. Ask it for a new ticket and it'll give you. Then ask it whether a ticket is still valid or expired. Or whether it is a fake. It'll know


"bagarino" sells you tickets and can tell a real ticket from a fake one. Simple, fast and RESTful. Ask it for a new ticket and it'll give you. Then ask it whether a ticket is still valid or expired. Or whether it is a fake. It'll know for sure. When tickets expire simply ask bagarino for new ones.

bagarino can be used as a support for a licensing server and as an helper to other systems in an authentication/authorization scenario.

npm install -g bagarino

bagarino needs Redis ( to be installed and running in order to work. To run bagarino use the following command:

sudo bagarino

bagarino is now up and running, listening for requests on port 8124.

Right out of the box bagarino is configured to run with default settings that make it listen on port 8124, protocol http, and log to /var/log.
These settings can be easily overridden by placing a file named "bagarino.conf" under /etc. This file must contain a valid JSON, organized as follows:

    "ENVIRONMENT": "production",
    "PORT": 8124,
    "HTTPS_PORT": 8443,
    "SERVER_TYPE": {
        "HTTPS": {
            "ENABLED": false,
            "KEY":  "private/key.pem",
            "CERT": "private/cert.crt"
        "HTTP": {
            "ENABLED": true
    "LOGGING": {
        "ENABLED": true,
        "PATH": "/var/log"
    "REDIS": {
        "HOST": "localhost",
        "PORT": 6379,
        "DB": 3

This file can be generated by calling sudo bagarino initconf.

The "ENVIRONMENT" key is passed to Nodejs and tells it whether to start in production or development mode.
The two keys "PORT" and "HTTPS_PORT" set on which port the server will be listening for incoming requests.
The "SERVER_TYPE" key enables one of the two modes bagarino can be started in, either simple HTTP or HTTPS.
The "HTTPS" sub-key has some more configuration in it as the paths to the key and certificate files must be provided.
Finally, the "LOGGING" key establishes under which folder the logs will be placed.

Here's a detailed guide on how to submit a request for creating new tickets and/or validating old ones.

Obtain a new ticket:

200 OK {"result":"OK","ticket":"7fd88ab09e40f99767e17df27a723d05562d573b","expires_in":100,"policy":"requests_based"}

See the status of the newly created ticket:

200 OK {"status":"VALID","expires_in":99,"policy":"requests_based"}

After some requests (99 more in this case) the ticket expires. Then, asking for it again will result in the following response:

200 OK {"status": "EXPIRED"}

Asking for a non-existent ticket results in the following:

404 Not Found {"status":"ERROR","cause":"not_found"}

By default new tickets have a time-based expire policy and a time-to-live of 60 seconds. A different policy can be used by specifying the "policy" parameter in query-string:

  • policy=time_based is the default one. Add "seconds=300" to make the ticket expire after the non-default delay of 5 minutes.
  • policy=requests_based makes the ticket expire after a certain amount of requests of its status you do to bagarino. By default it's 100 requests, but you can otherwise specify e.g. "requests=500" to make it last for 500 requests.
  • policy=cascading makes the ticket depend on another one: once the dependency ticket expires the dependent one does as well.
  • policy=manual_expiration makes the ticket perpetual, unless you make it expire manually by calling the "expire" verb (explained some lines below).
  • policy=bandwidth_based makes the ticket perpetual as well, but the number of requests for it that can be done within a minute is limited.

Let's see some requests that create tickets with different expiration policies:

200 OK {"result":"OK","ticket":"62a315cd7bdae5e84567cad9620f82b5defd3ef0","expires_in":5,"policy":"requests_based"}

200 OK {"result":"OK","ticket":"0b4e20ce63f7de9a4a77910e7f909e5dba4538f3","expires_in":100,"policy":"requests_based"}

200 OK {"result":"OK","ticket":"50ab14d6f5dd082e8ed343f7adb5f916fa76188a","expires_in":120,"policy":"time_based"}

200 OK {"result":"OK","ticket":"9ae23360fb4e9b3348917eb5e9b8a8e725b0dcb0","depends_on":"f073145dfdf45a6e85d0f758f78fd627fa301983","policy":"cascading"}

200 OK {"result":"OK","ticket":"f57d75c23f6a49951a6e886bbc60de74bc02ef33","policy":"manual_expiration"}

When using the manual expiration policy you must call an appropriate verb to make the ticket expire:

200 OK {"status":"EXPIRED"}

Subsequent requests for that ticket will give an "EXPIRED" status.

Finally, bandwidth-based tickets can be created with the following requests:

200 OK {"result": "OK", "ticket": "2966c1fc73a0d78c96bdc18fb67ed99af1356b8a", "requests_per_minute": 100, "policy": "bandwidth_based"}

Asking for a ticket status is all you can do with a newly created ticket. bagarino will answer with three different statuses:


The answer will carry some more info when the ticket is still valid:

200 OK {"status":"VALID","expires_in":99,"policy":"requests_based"}

In the previous example the expiration policy and the TTL (Time-To-Live) of the ticket are returned, as well as its status. The parameter "expires_in" has to be read based on the policy of the ticket:

  • When the policy is time_based then "expires_in" is the number of seconds before the ticket expires
  • When the policy is requests_based the value of "expires_in" is the number of requests before the ticket expires

Expired tickets are kept in memory by bagarino for 10 days. After that time a call to their status will return "NOT_VALID" as it would for a ticket that didn't exist in the first place.

Even tickets with a policy other than "manual_expiration" can be forcibly ended by calling the expire verb, provided that they had been created with an ad-hoc option, "can_force_expiration":

200 OK {"result": "OK", "ticket": "d81d9b01e323510ba919c0f54fbfba5b7903e326", "expires_in": 100, "policy": "requests_based"}

The result will look identical to any other requests_based-policied ticket but the can_force_expiration option enables the call to the expire verb to successfully end this ticket life:

200 OK {"status": "EXPIRED"}

Creating the ticket without this option and subsequently calling expire would have produced the following error:

400 Bad Request {"status": "ERROR", "cause": "different_policy"}

It's possible to create more tickets at once by adding the paramenter "count" to the query-string of the verb new, followed by the number of tickets to be created. The maximum number of tickets that can be created this way is capped to prevent overloading the system. Here's a typical request for mass-creation of tickets:

200 OK {"result":"OK","tickets":["9c7800ec9cf053e60674042533710c556fe22949","3cd5da62c2ba6d2b6b8973016264282f61f4afdd","7207c7effb2bd8fd97b885a4f72492a97e79babf","75a6cf2ba0454dfe74a4d6ce8baa80881fb76005"],"expire_in":60,"policy":"time_based"}

Sometimes it may be useful to bound one or more tickets to a "context" so they only acquire a meaning under certain conditions. In bagarino this is done by attaching a textual context to the ticket during the "new" operation:

200 OK {"result":"OK","ticket":"7486f1dcf4fc4d3c4ef257230060aea531d42758","expires_in":100,"policy":"requests_based"}

Once it's scoped this way requests for that ticket status that don't specify the context won't be able to retrieve it, resulting in a "not_found" error, the same given when asking for a non-existent ticket:

404 Not Found {"status":"ERROR","cause":"not_found"}

The way to ask for a context-bound token is as follows:

200 OK {"status":"VALID","expires_in":99,"policy":"requests_based"}

A ticket created with the option autorenew=true automatically generates a new one right before expiring. Only requests-based ones can be decorated at creation with the additional option "autorenew". When this option is true bagarino automatically spawns a new ticket when the old one's expiration is one request away, returning this newly created one alongside the validity/expiration info of a "status" request. The new ticket's policy and initial TTL will be the same as the old one's.

Here's how an autorenew ticket is created:

200 OK {"result":"OK","expires_in":10,"ticket":"0cca33a81e4ce168f218d74692e096c676af2a25","policy":"requests_based"}

After asking 9 times for this ticket validity here's what happens asking one more time:

200 OK {"status":"VALID","expires_in":0,"policy":"requests_based","next_ticket":"c7433c48f56bd224de43b232657165842609690b"}

A new ticket, c7433c48f56bd224de43b232657165842609690b, is born, right when the old one expires and with the same policy and initial TTL (i.e. 10 requests).

Generating a ticket takes some CPU time and, under certain circumstances, this may be an issue. To arbitrarily reduce generation time a feature is present in bagarino that can be activated by passing certain values to the optional "generation_speed" parameter.

200 OK

200 OK

200 OK

Notice how the format of the tickets is different for every approach: that's a direct consequence of the speed the tickets are generated.
When no generation speed is specified the default slow one is used.
It's almost superfluous to note that faster generation speeds are more subject to weak tickets that can conflict across an eventual multi-bagarinos environment.
Viceversa, slower generation speeds are more CPU-demanding although giving birth to strong tickets that are almost unique.

Sometimes checking a ticket validity directly influences its status: in particular requests- or bandwidth-based tickets have policies that put a direct correlation between the number of times a "status" check is called for them and their validity itself.

There may be times when it's needed to check whether a ticket with one of these policies is valid or not, without affecting its status.
At those times a "status" call can be expanded with a "light" parameter, like this:

200 OK {"status":"VALID","expires_in":100,"policy":"requests_based"}

The net result, in this case for a requests-based ticket, is the call not affecting the remaining number of times the "status" call can be made for this ticket. I.e. Calling status on it again will show the same number of remaining "status" checks:

200 OK {"status":"VALID","expires_in":100,"policy":"requests_based"}

Almost the same applies to bandwidth-based tickets, except that, for them, the number of "status" checks resets every minute.

In bagarino version 1.10.2 a new utility call has been added, that can be used to retrieve which policy a ticket responds to:

200 OK {"policy":"**requests_based**","more":{"autorenew":false,"generation_speed":"slow","can_force_expiration":false}}

This way the policy for that ticket can be retrieved without the need to issue a "status" call on it.
You can notice that the response to a "policy" call carries some additional info about other parameters driving the ticket behavior.
In fact, the "more" object contains a list of settings for this ticket other than the policy type. For explanations about any of them see the paragraphs above in this same guide.

Under some circumstances it may happen that one or more tickets become stale and continue to be tracked by bagarino even if they aren't active anymore.
A command-line switch can be used to remove them all at once, but pay attention to some potential issues:

  • stale tickets can't be recovered after they got deleted by a garbage collection
  • a big number of stale tickets (> 100K) may cause the garbage collection to degrade bagarino performances until the cleanup ends

Here's the command-line that activates the garbage collection:

bagarino gc


bagarino gcv

The latter is much (very much!) verbose, reporting progress for every stale ticket being deleted, so be careful when using it.

Here's an example response from bagarino gc:

Starting garbage collection...
Got 12 key(s) to analyze...
Garbage Collection performed correctly.
1 stale ticket(s) cleaned.

Copyright (c) 2015 Nicola Orritos

Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.