What are the different scenarios to plan for when using $allowAnonymous in a controller?
Here are the new constants that Craft 3.2 introduced:

const ALLOW_ANONYMOUS_NEVER = 0;
const ALLOW_ANONYMOUS_LIVE = 1;
const ALLOW_ANONYMOUS_OFFLINE = 2;


By default every controller will have the following property:

protected $allowAnonymous = self::ALLOW_ANONYMOUS_NEVER;


And you can override it in your controller in various ways:

// Allow anonymous access to all actions only when the site is live
public $allowAnonymous = true;

// Allow anonymous access to the `preview` action only when the site is live
public $allowAnonymous = ['preview'];

// Allow anonymous access to the `preview` action only when the site is live
public $allowAnonymous = ['preview' =&gt; self::ALLOW_ANONYMOUS_LIVE];

// Allow anonymous access to the `preview` action only when the site is offline
public $allowAnonymous = ['preview' =&gt; self::ALLOW_ANONYMOUS_OFFLINE];

// Allow anonymous access to the `preview` action when the site is live or offline
public $allowAnonymous = ['preview' =&gt; self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE];


The single pipeline | is a bitwise OR operator. It compares each bit (a binary digit of 0 or 1) in the integers and returns a new integer with a 1 wherever either numbers had a 1, and a 0 anywhere else (similar to how the || operator campares booleans). So the expression self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE is the same as 1 | 2 and will evaluate to 3. Here are some examples of how the | bitwise operator works:

( 0 = 0000) | ( 0 = 0000) =&gt; ( 0 = 0000)
( 0 = 0000) | ( 1 = 0001) =&gt; ( 1 = 0001)
( 0 = 0000) | ( 2 = 0010) =&gt; ( 2 = 0010)
( 1 = 0001) | ( 1 = 0001) =&gt; ( 1 = 0001)
( 1 = 0001) | ( 2 = 0010) =&gt; ( 3 = 0011)
( 2 = 0010) | ( 2 = 0010) =&gt; ( 2 = 0010)


The init() method of the Craft base controller now normalizes the value as follows:

// Normalize $allowAnonymous
if (is_bool($this-&gt;allowAnonymous)) {
    $this-&gt;allowAnonymous = (int)$this-&gt;allowAnonymous;
} else if (is_array($this-&gt;allowAnonymous)) {
    $normalized = [];
    foreach ($this-&gt;allowAnonymous as $k =&gt; $v) {
        if (
            (is_int($k) &amp;&amp; !is_string($v)) ||
            (is_string($k) &amp;&amp; !is_int($v))
        ) {
            throw new InvalidArgumentException("Invalid \$allowAnonymous value for key \"{$k}\"");
        }
        if (is_int($k)) {
            $normalized[$v] = self::ALLOW_ANONYMOUS_LIVE;
        } else {
            $normalized[$k] = $v;
        }
    }
    $this-&gt;allowAnonymous = $normalized;
} else if (!is_int($this-&gt;allowAnonymous)) {
    throw new InvalidConfigException('Invalid $allowAnonymous value');
}


Source: https://github.com/craftcms/cms/blob/3.2.2/src/web/Controller.php#L75-L96

So if the value is a boolean then false will be normalized to 0, whereas true will be normalized to 1.

If the value is an array then each key-value pair in the array will be inspected. If the key is an integer then the value is set to 1, for example:

public $allowAnonymous = ['preview'];


equates to

public $allowAnonymous = [0 =&gt; 'preview'];


and is interpreted as 

public $allowAnonymous = ['preview' =&gt; self::ALLOW_ANONYMOUS_LIVE];


If the key is a not an integer then the key-value pair is left as is.

Here is how $allowAnonymous is enforced:

// Enforce $allowAnonymous
$isLive = Craft::$app-&gt;getIsLive();
$test = $isLive ? self::ALLOW_ANONYMOUS_LIVE : self::ALLOW_ANONYMOUS_OFFLINE;

if (is_int($this-&gt;allowAnonymous)) {
    $allowAnonymous = $this-&gt;allowAnonymous;
} else {
    $allowAnonymous = $this-&gt;allowAnonymous[$action-&gt;id] ?? self::ALLOW_ANONYMOUS_NEVER;
}

if (!($test &amp; $allowAnonymous)) {
    // Prevent access unless the user is logged in and has the required permissions to view the site
}


Source: https://github.com/craftcms/cms/blob/3.2.2/src/web/Controller.php#L147-L176

The single ampersand &amp; is a bitwise AND operator. It compares each bit in the integers and returns a new integer with a 1 wherever both numbers have a 1, and a 0 anywhere else (similar to how the &amp;&amp; operator campares booleans). Here are some examples of how the &amp; bitwise operator works:

( 0 = 0000) &amp; ( 0 = 0000) =&gt; ( 0 = 0000) =&gt; false
( 0 = 0000) &amp; ( 1 = 0001) =&gt; ( 0 = 0000) =&gt; false
( 0 = 0000) &amp; ( 2 = 0010) =&gt; ( 0 = 0000) =&gt; false
( 1 = 0001) &amp; ( 1 = 0001) =&gt; ( 1 = 0001) =&gt; true
( 1 = 0001) &amp; ( 2 = 0010) =&gt; ( 0 = 0000) =&gt; false
( 2 = 0010) &amp; ( 2 = 0010) =&gt; ( 2 = 0010) =&gt; true
( 3 = 0011) &amp; ( 1 = 0001) =&gt; ( 1 = 0001) =&gt; true
( 3 = 0011) &amp; ( 2 = 0010) =&gt; ( 2 = 0010) =&gt; true
( 3 = 0011) &amp; ( 3 = 0011) =&gt; ( 3 = 0011) =&gt; true


By enforcing the condition $test &amp; $allowAnonymous, we can check that $test (whether the site is live or offline) and $allowAnonymous (the permissions granted to the specific controller action) overlap.

More on bitwise operators here.



I'm not sure what the specific issue with your plugin is , but as far as I can tell the only thing that changed in Craft 3.2 was that the ALLOW_ANONYMOUS_OFFLINE constant was added, allowing for (but not requiring) more specific permissions on controller actions.