Swiftpack.co - Package - skelpo/JWTMiddleware


Handles authentication and authorization of models through JWT tokens by themselves or mixed with other authentication methods.


Add this line to your manifest's dependencies array:

.package(url: "https://github.com/skelpo/JWTMiddleware.git", from: "0.6.1")

And add JWTMiddleware to all the target dependency arrays you want to access the package in.

Complete the installation by running vapor update or swift package update.


There are currently 2 modules in the JWTMiddleware package; JWTMiddleware and JWTAuthenticatable.

The JWTMiddleware module contains middleware for request authentication/authorization and helpers for getting data stored in the request by the middleware.

The JWTAuthenticatable module holds protocols that allow a type to be authenticated/authorized in the middleware declared in the JWTMiddleware module.


The JWTMiddleware module exports the following types:

  • JWTAuthenticatableMiddlware:

    Handles authenticating/authorizing a model conforming to JWTAuthenticatable using data pulled from a request.

    When a request is passed though the middleware, it will first check to see if the specified model is already authenticated. If it is not, it will try to get data to authenticate the model by calling the static authBody(from:) method. If it successfully authenticates, it will get the model's access token by calling accessToken(on:), then store both the token and the authenticated model in the request for accessing later. If nil is return from authBody(from:), then we try to authenticate using data from the Authorization: Bearer ... header. If authentication succeeds, we will store both the token fetched from the header and the authenticated model in the request.

    You can register the middleware to a route group as shown below.

     let auth = route.group(JWTAuthenticatableMiddlware<User>())
  • JWTVerificationMiddleware:

    Gets the value from the Authorization: Bearer ... header, verifies it with the specified payload type, and stores it in the request for later.

  • RouteRestrictionMiddleware:

    Restricts access to routes based on a user's permission level (i.e. Admin, Moderator, Standard, etc.)

    		restrictions: [
    			RouteRestriction(.DELETE, at: "users", User.parameter, allowed: [.admin, .moderator]),
    		parameters: [User.routingSlug: User.resolveParameter]

    You must add custom parameter types used due to the way the request's URI and the restrictions path components are checked. Default parameter types are added by default.

    If a user is authenticated via middleware before RouteRestrictionMiddleware, the middleware will use that user's ID to check against the ID in the JWT payload we checking a request.

  • RouteRestriction:

    A restriction constraint for a RouteRestrictionMiddleware instance. The initializer takes in an optional method, a path, and valid permission levels for that path. If the method is nil, any method for the given path will be restricted.

    RouteRestriction(.GET, at: "dashboard", "user", User.parameter, "tickets", allowed: [.admin])
  • PermissionedUserPayload:

    Extends IdentifiableJWTPayload adding a


The JWTAuthenticatable module exports the following types:

  • IdentifiableJWTPayload:

    Represents a JWT payload with an id value. This is used by the BasicJWTAuthenticatable to access a model from the database based on its id property.

  • JWTAuthenticatable:

    A model that can be authorized with a JWT payload and authenticated with an unspecified type that is defined by the implementing type.

    This protocol requires the following types/properties/methods:

    • associatedtype AuthBody: Used for authentication of the model.

    • associatedtype Payload: IdentifiableJWTPayload: A type that the payload of a JWT token can be converted to. This type is used to authorize requests.

    • accessToken(on request: Request) throws -> Future<Payload>: This method should create a payload for a JWT token that will later be used to authorize the model.

    • static authBody(from request: Request)throws -> AuthBody?: Gets data from a request that can be used to authenticate a model

    • static authenticate(from payload: Payload, on request: Request)throws -> Future<Self>: Verifies the payload passed in and gets an instance of the model based on the payload's contents.

    • static authenticate(from body: AuthBody, on request: Request)throws -> Future<Self>: Gets a model and checks it against the contents of the body parameter passed in.

  • BasicJWTAuthenticatable:

    Implements JWTAuthenticatable methods for authenticating with an id/password combination. The ID should either be a username or email.

    The authBody method implementation gets the name of the property referenced by the usernameKey key-path. It will then extract the values from the request body with the key from usernameKey and "password".

    The payload authorization method simply finds the instance of the model stored in the database with an ID equal to the id property in the payload.

    The AuthBody authentication method fetches the first user from the database with a usernameKey property equal to the body.username value. It then checks to see if the model's password hash is equal to the body.password value, using BCrypt verification.

    This protocols requires the following type/properties:

    • associatedtype Payload: IdentifiableJWTPayload: A type that the payload of a JWT token can be converted to. This type is used to authorize requests.
    • usernameKey: KeyPath<Self, String>: The key-path for the property that will be checked against the body.username value during authentication. This will usually be either an email or username. This property can be either a variable or constant.
    • var password: String The hashed password of the model, used to verify the request'c credibility. This properties value must be hash using BCrypt.

This module also adds some helper methods to the Request type:

  • accessToken()throws -> String: Gets the value of the Authorization: Bearer ... header.
  • payload<Payload: Decodable>(as payloadType: Payload.Type = Payload.self)throws -> Payload: Gets the payload of a JWT token the was previously stored in the request by a middleware.
  • payloadData<Payload, Object>(storedAs stored: Payload.Type, convertedTo objectType: Object.Type = Object.self)throws -> Object: Gets the payload of a JWT token stored in the request and converts it to a different type.


Stars: 28



Release Candidate 1 - 2020-03-16 17:02:29

  • Fully ready for Vapor 4
  • Has tests now
  • Switching to the Vapor style of semver
  • CI enabled
  • Repo cleaned up

v0.10.0 Dependencies Updated - 2019-07-16 12:11:27

v0.9.0 - 2018-12-07 14:49:20

Type Less, Type Less

Removed the Status generic type from PermissionsMiddleware because we can get that type information from the Payload generic type.

We also create a static String.payloadKey value so the key where the JWT payload is stored is type safe.

In the JWTVerificationMiddleware, if an Authorization header is not found, status code 402 (Unauthorized) is returned instead of 400 (Bad Request).

v0.8.2 - 2018-10-16 08:08:11

Adjusting usernameKey to now be a WritableKeyPath

Thanks @Joebayld

v0.8.1 - 2018-07-26 13:23:50

Back to Where it Came From

In the JWTStorageMiddleware, we where pulling the payload from the request's private container, saving it back again, and continuing. Yeah, not point in doing that!

So now we get the JWT from the auth header, verify it, and store the payload in the request's private container. A much better idea.

v0.8.0 - 2018-06-21 11:39:34

The Middleware Became Agnostic

RouteRestrictionMiddleware was deemed to restrictive and relied to heavily on the parent route path. It has been replaced with PermissionsMiddleware and any route registered with the middleware is protected by it, making it agnostic to the route path it is on.

v0.7.0 - 2018-05-17 22:22:48

This Route is Rather Restricting

And it should be, considering admins should be the only ones supposed to access the data. And you can add this functionality yourself, with RouteRestrictionMiddeware:

    restrictions: [
        RouteRestriction(.DELETE, at: "users", User.parameter, allowed: [.admin, .moderator]),
    parameters: [User.routingSlug: User.resolveParameter]

v0.6.1 - 2018-05-09 16:54:09

If They Break it, You Must Unbreak it.

The Auth package's Authenticatable protocol no longer requires conformance to Model, so we add it ourselves to JWTAuthenticatable: https://github.com/skelpo/JWTMiddleware/pull/9

v0.6.0 - 2018-05-07 20:32:22

Vapor Things: Season 3

Lets get away from the strangness of betas for a while. We now use the official Vapor 3.0 release.

v0.5.0 - 2018-05-02 20:07:51

Non-Generic JWT Verification

  • Renamed JWTVerificationMiddleware<Payload> to JWTStorageMiddleware<Payload>
  • Created JWTVerificationMiddleware which only verifies the access token. No storing.
  • Fixed typo in name of JWTAuthenticatableMiddleware (@jimmya)

v0.4.1 - 2018-04-26 20:49:39

Only Work with Existing Data

You should only decode a request's body if it exists, so we make sure there is one before we do by checking whether the HTTP method allows for it. Only if the answer is 'yes' do we decode.

v0.4.0 - 2018-04-26 20:48:08

Manipulating the Future

Decoding optional value from a request body only works when decoding asynchronously, so JWTAuthenticatable.authBody(from:) now returns a Future<AuthBody?>.

v0.3.1 - 2018-04-26 20:46:44

Let ~No~ Some User Pass

When you try to get the password value from a request using the passwrod key, it just don't work. Typo's fixed now!

v0.3.0 - 2018-04-26 20:45:25

Request: The Final Message

There are 3 new extension methods added to Vapor's Request object:

  • accessToken()throws -> String
  • payload<Payload: Decodable>(as payloadType: Payload.Type = Payload.self)throws -> Payload
  • payloadData<Payload, Object>(storedAs stored: Payload.Type, convertedTo objectType: Object.Type = Object.self)throws -> Object where Payload: Encodable, Object: Decodable

v0.2.2 - 2018-04-20 16:26:14

README All the Docs

The README should contain the the necessary documentation now.

When you add the JWTMiddleware library to a target, you can now import both the JWTMiddleware and JWTAuthenticatable modules. The JWTMiddleware target also exports the JWTAuthenticatable module.

v0.2.1 - 2018-04-19 19:16:04

Instructions Below

Find out about it in the README.