NAME

Mojolicious::Plugin::OpenAPI::Guides::Security - How to secure your API

OVERVIEW

This guide will give you an introduction on how to use the security features in OpenAPI, together with Mojolicious::Plugin::OpenAPI.

Note that this is currently EXPERIMENTAL! Please let me know if you have any feedback. See https://github.com/jhthorsen/mojolicious-plugin-openapi/pull/40 for a complete discussion.

TUTORIAL

Specification

Here is an example specification that use securityDefinitions and security from the OpenAPI spec:

{
  "swagger": "2.0",
  "info": { "version": "0.8", "title": "Super secure" },
  "schemes": [ "https" ],
  "basePath": "/api",
  "securityDefinitions": {
    "dummy": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header",
      "description": "dummy"
    }
  },
  "paths": {
    "/protected": {
      "post": {
        "x-mojo-to": "super#secret_resource",
        "security": [{"dummy": []}],
        "parameters": [
          { "in": "body", "name": "body", "schema": { "type": "object" } }
        ],
        "responses": {
          "200": {"description": "Echo response", "schema": { "type": "object" }},
          "401": {"description": "Sorry mate", "schema": { "type": "array" }}
        }
      }
    }
  }
}

Application

The specification above can be dispatched to handlers inside your Mojolicious application. The do so, add the "security" key when loading the plugin, and reference the "securityDefinitions" name inside that to a callback. In this example, we have the "dummy" security handler:

package Myapp;
use Mojo::Base "Mojolicious";

sub startup {
  my $app = shift;

  $app->plugin(OpenAPI => {
    url      => "data://main/sec.json",
    security => {
      dummy => sub {
        my ($c, $definition, $scopes, $cb) = @_;
        return $c->$cb() if $c->req->headers->authorization;
        return $c->$cb('Authorization header not present');
      }
    }
  });
}

1;

$c is a Mojolicious::Controller object. $definition is the security definition from /securityDefinitions. $scopes is the Oauth scopes, which in this case is just an empty array ref, but it will contain the value for "security" under the given HTTP method.

Call $cb with undef or no argument at all to indicate pass. Call $cb with a defined value (usually a string) to indicate that the check has failed. When none of the sets of security restrictions are satisfied, the standard OpenAPI structure is built using the values passed to the callbacks as the messages and rendered to the client with a status of 401.

Note that the callback must be called or the dispatch will hang.

TODO: If after all of the checks have been performed, no set of requirements are satisfied then the a 401 error will be rendered. Any exceptions that are thrown will result in a 500 being rendered.

The first thing in your code that you need to do is to load this plugin and the "Specification". See "register" in Mojolicious::Plugin::OpenAPI for information about what the plugin config can be.

See also "SYNOPSIS" in Mojolicious::Plugin::OpenAPI for example Mojolicious::Lite application.

Controller

Your controllers and actions are unchanged. The difference in behavior is that the action simply won't be called if you fail to pass the security tests.

SEE ALSO

Mojolicious::Plugin::OpenAPI, https://openapis.org/specification.