Securing a Swagger API with OAuth2

In our previous article on Swagger, we defined a Player API modelling GET access to a Player resource. In this article, I show how to use Swagger’s security models to to deploy this API using an OAuth2 configuration.

Swagger handles authentication and authorization using a combination of a “Security Definitions” Object and a list of “Security Requirements” Objects. Each of these definitions are applied at the top-level of your Swagger specification.

For example, the following JSON swagger spec adds empty security definitions and requirements objects to the API.

{
    "swagger": "2.0",
    "info": {
        "title": "Player API",
        "description": "A simple API for Player resources",
        "version": "1.0.1",
    },
    "securityDefinitions": {},
    "security": {},
    "paths": {
        ...
    }
}

Our goal, then, is to fill in these empty objects with a valid OAuth2 configuration. We start with the securityDefinitions, which lists the available security methods that clients may use to access this API. Each security method is associated with a name, and each named method defines the full specification of the security method. For example, you can list define both an OAuth2 authorization method and an API key authorization method for your API. In the following example, we declare the auth methods for our API as a valid API key present in the request header, and an OAuth2 method using the implicit OAuth2 flow using the http://api.example.com/api/auth/ URL.

{
    "swagger": "2.0",
    "info": {
        "title": "Player API",
        "description": "A simple API for Player resources",
        "version": "1.0.1",
    },
    "securityDefinitions": {
        "api_key": {
            "type": "apiKey",
            "name": "api_key",
            "in": "header"
        },
        "oauth": {
            "type": "oauth2",
            "authorizationUrl": "http://api.example.com/api/auth/",
            "flow": "implicit",
            "scopes": {
                "read:players": "read player data"
            }
        }
    },
    "security": {},
    "paths": {
        ...
    }
}

The actual mechanics of filling in the OAuth2 configuration will vary per your implementation. Now, given the defined security definitions, you can apply them to your API on a per-API or per-operation basis. The following full example shows how to apply the OAuth method to a particular path in your API. As part of the security field for the operation, you list the security methods to apply. For OAuth2, you also list the OAuth scopes that apply for this operation.

{
    "swagger": "2.0",
    "info": {
        "title": "Player API",
        "description": "A simple API for Player resources",
        "version": "1.0.1",
    },
    "securityDefinitions": {
        "oauth": {
            "type": "oauth2",
            "authorizationUrl": "http://api.example.com/api/auth",
            "flow": "implicit",
            "scopes": {
                "read:players": "read player data"
            }
        }
    },
    "paths": {
        "/player/{id}": {
            "get": {
                "description": "Returns a Player resource",
                "produces": [
                    "application/json"
                ],
                "responses": {
                    "200": {
                        "description": "A player resource.",
                        "schema": {
                            "$ref": "#/definitions/Player"
                        }
                    }
                },
                "security": [
                    "oauth": ["read:players"]
                ]
            },
            "parameters": [{
                "name": "id",
                "in": "path",
                "description": "Identifier of player to retreive",
                "required": true,
                "type": "string"
            }]
        }
    },
    "definitions": {
        "Player": {
            "type": "object",
            "properties": {
                "playerId": {
                    "type": "string"
                },
                "alias": {
                    "type": "string"
                },
                "displayName": {
                    "type": "string"
                },
                "profilePhotoUrl": {
                    "type": "string"
                }
            },
            "required": ["playerId", "alias"]
        }
    }
}

Like this post? Subscribe via RSS or email to never miss an update.