Writing OpenAPI (Swagger) Specification Tutorial Series - Part 6
Defining Security
By Arnaud Lauret, May 22, 2016
After mastering input and output modeling like a Jedi, let’s see how we can describe API’s security with the OpenAPI specification’s.
Writing OpenAPI (Swagger) Specification Tutorial Series
This tutorial teaches everything about the OpenAPI 2.0 Specification (fka. as Swagger), most of what you’ll read here can still be applied on version 3.
If you’re a bit lost in the specification (version 2 or 3), take a look at the OpenAPI Map:
In previous parts we’ve learned to write efficiently highly accurate interface description, in this seventh part we’ll learn how to describe how an API is secured.
Security definitions
Following (almost) the same principle used with parameters and definitions, security can be defined and then used on different levels.
Security definition takes place on specification’s root level in securityDefinition section. It contains a list of named security definitions. Each definition can be of type:
basicfor Basic AuthenticationapiKeywhen using an API key to secure the APIoauth2for Oauth 2
Basic Authentication
To define a basic security it’s fairly easy, we only have to set its type to basic:
securityDefinitions:
UserSecurity:
type: basic
AdminSecurity:
type: basic
MediaSecurity:
type: basic
In this example we have defined three security definitions (UserSecurity, AdminSecurity and MediaSecurity), each of them is of basic type.
API Key
To define an apiKey security we have to:
- Set
typetoapiKey - Indicate where the API ley is located with
in. An API can be in aheaderor aqueryparameter - And then give the parameter’s
name
securityDefinitions:
UserSecurity:
type: apiKey
in: header
name: SIMPLE-API-KEY
AdminSecurity:
type: apiKey
in: header
name: ADMIN-API-KEY
MediaSecurity:
type: apiKey
in: query
name: media-api-key
In this example, we have defined three security definitions of apiKey type:
UserSecurityuses aheaderparameter namedSIMPLE-API-KEYAdminSecurityuses aheaderparameter namedADMIN-API-KEYMediaSecurityuses aqueryparameter namedmedia-api-key
Oauth 2
Flow and URLs
When defining an oauth2 security definition, we can define the Oauth2 flow used and corresponding authorizationUrl and/or tokenUrl depending on the chosen flow:
| Flow | Required URLs |
|---|---|
| implicit | authorizationUrl |
| password | tokenUrl |
| application | tokenUrl |
| accessCode | authorizationUrl and tokenUrl |
securityDefinitions:
OauthSecurity:
type: oauth2
flow: accessCode
authorizationUrl: 'https://oauth.simple.api/authorization'
tokenUrl: 'https://oauth.simple.api/token'
In this example we have defined a OauthSecurity security definition of oauth2 type using an accessCode flow with an authorizationUrl and a tokenUrl.
Scopes
We can also define scopes by using a hashmap, the key is the scope’s name and the value is its description.
securityDefinitions:
OauthSecurity:
type: oauth2
flow: accessCode
authorizationUrl: 'https://oauth.simple.api/authorization'
tokenUrl: 'https://oauth.simple.api/token'
scopes:
admin: Admin scope
user: User scope
media: Media scope
In this example, we’ve added three scopes (admin, user and media) to our OauthSecurity security definition
Using security definitions
Once we have described security definitions in securityDefinition we can apply them to the overall API or to specific operations with the security sections.
When we apply a security definition to an operation, it overrides API security.
Basic Authentication
Let’s see how we can use a basic security definition.
API level
In this example the security definition which apply to ALL API operations is UserSecurity:
securityDefinitions:
UserSecurity:
type: basic
AdminSecurity:
type: basic
MediaSecurity:
type: basic
security:
- UserSecurity: []
paths:
/persons:
Operation level
As GET /persons operation do not define a security, it’s the UserSecurity defined on top level which applies:
paths:
/persons:
parameters:
- $ref: '#/parameters/userAgent'
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
parameters:
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/pageNumber'
- $ref: '#/parameters/includeNonVerifiedUsers'
- $ref: '#/parameters/sortPersons'
On POST /persons operation, the top level security is overridden by AdminSecurity:
post:
summary: Creates a person
description: Adds a new person to the persons list.
security:
- AdminSecurity: []
On POST /images operation, the top level security is also overridden, but this time it’s by MediaSecurity:
/images:
parameters:
- $ref: '#/parameters/userAgent'
post:
summary: Uploads an image
security:
- MediaSecurity: []
API Key
We can do exactly the same things with an API key security definition.
API level
In this example the security definition which apply to ALL API operations is UserSecurity:
securityDefinitions:
UserSecurity:
type: apiKey
in: header
name: SIMPLE-API-KEY
AdminSecurity:
type: apiKey
in: header
name: ADMIN-API-KEY
MediaSecurity:
type: apiKey
in: query
name: media-api-key
security:
- UserSecurity: []
paths:
/persons:
Operation level
As GET /persons operation do not define a security, it’s the UserSecurity defined on top level which applies:
paths:
/persons:
parameters:
- $ref: '#/parameters/userAgent'
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
parameters:
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/pageNumber'
- $ref: '#/parameters/includeNonVerifiedUsers'
- $ref: '#/parameters/sortPersons'
On POST /persons operation, the top level security is overridden by AdminSecurity:
post:
summary: Creates a person
description: Adds a new person to the persons list.
security:
- AdminSecurity: []
On POST /images operation, the top level security is also overridden, but this time it’s by MediaSecurity:
/images:
parameters:
- $ref: '#/parameters/userAgent'
post:
summary: Uploads an image
security:
- MediaSecurity: []
Oauth 2
With an oauth2 the principle is the same but you can also define which scope(s) you use.
API level
In this example the security definition which apply to ALL API operations is OauthSecurity with the user scope:
securityDefinitions:
OauthSecurity:
type: oauth2
flow: accessCode
authorizationUrl: 'https://oauth.simple.api/authorization'
tokenUrl: 'https://oauth.simple.api/token'
scopes:
admin: Admin scope
user: User scope
media: Media scope
security:
- OauthSecurity:
- user
paths:
/persons:
Operation level
As GET /persons operation do not define a security, it’s the OauthSecurity with userscope defined on top level which applies:
paths:
/persons:
parameters:
- $ref: '#/parameters/userAgent'
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
parameters:
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/pageNumber'
- $ref: '#/parameters/includeNonVerifiedUsers'
- $ref: '#/parameters/sortPersons'
On POST /persons operation, the top level security scope is overridden by admin:
post:
summary: Creates a person
description: Adds a new person to the persons list.
security:
- OauthSecurity:
- admin
On POST /images operation, the top level security is also overridden, but this time it’s by media:
Using multiple security types
It’s not mandatory to define a single type of security definition and use only one at a time. The examples below show how we can define security definitions of different types and use more than one on operations.
Security definitions
Here we define there different types of security:
securityDefinitions:
OauthSecurity:
type: oauth2
flow: accessCode
authorizationUrl: 'https://oauth.simple.api/authorization'
tokenUrl: 'https://oauth.simple.api/token'
scopes:
admin: Admin scope
user: User scope
MediaSecurity:
type: apiKey
in: query
name: media-api-key
LegacySecurity:
type: basic
Global security
Then we choose to apply both of them globally:
It means that a consumer can call any operation (which do not override security) with one of those two security types.
Overriding global security
As GET /persons operation do not define a security, it’s the Oauth 2 OauthSecurity with userscope OR the basic authentication LegacySecurity defined on top level which applies:
paths:
/persons:
parameters:
- $ref: '#/parameters/userAgent'
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
parameters:
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/pageNumber'
- $ref: '#/parameters/includeNonVerifiedUsers'
- $ref: '#/parameters/sortPersons'
On POST /persons operation, the top level security scope Oauth 2 OauthSecurity is overridden by admin and consumer can also still use the basic authentication LegacySecurity:
post:
summary: Creates a person
description: Adds a new person to the persons list.
security:
- OauthSecurity:
- admin
- LegacySecurity: []
On POST /images operation, the top level security is fully overridden by the API Key MediaSecurity:
Conclusion
You now have mastered security. With this new post you are now a full expert when it comes to describe an API interface with the OpenAPI specification. But an interface contract alone may not be easy to understand without some explainations. In next post we’ll learn how to document this interface description to ease its understanding.
