Getting Started¶
Vapor's Auth Provider package makes implementing authentication and authorization easy and secure. It supports common auth patterns such as:
- Token (bearer) authentication
- Username + password (basic) authentication
- Permission-based authorization
- Session-based persistance
Auth's modular, protocol-based nature also makes it a great foundation for custom auth needs.
Tip
Use vapor new <name> --template=vapor/auth-template
to create a new project template with AuthProvider and samples included.
Package¶
To use Auth, you will need to have the Auth Provider added to your project.
This is as simple as adding the following line to your Package.swift
file.
.Package(url: "https://github.com/vapor/auth-provider.git", ...)
Check out the Package section for more information.
Example¶
Let's take a look at how we can implement a simple, token-based authentication system using Vapor and Auth.
User¶
We will start by creating a model to represent our user. If you already have a user class, you can skip this step.
import Vapor import FluentProvider final class ExampleUser: Model { let name: String ... } extension ExampleUser: Preparation { ... }
Here we create a very simple user with just one property: a name.
Seealso
We're omitting most of Model
and Preparation
protocol requirements. Check out Fluent's
Getting Started for more information about these protocols.
Token¶
Next let's create a model to represent our authentication tokens. These will be stored in a separate database table or collection called "tokens".
When a user logs in, we will create a new token for them. They will then use this token on subsequent requests instead of their username and password.
For now, here's what our simple token model will look like.
import Vapor import FluentProvider final class ExampleToken: Model { let token: String let userId: Identifier var user: Parent<ExampleToken, ExampleUser> { return parent(id: userId) } ... } extension ExampleToken: Preparation { ... }
This token has two properties:
- token: a unique, random string that we will send in requests
- userId: the identifier for the user to whom this token belongs
Seealso
We're using Fluent relations here. Check out Fluent's Relations section for more information.
Token Authenticatable¶
Now that we have our example user and token, we can make our user authenticatable with the token.
This might sound complicated, but it's actually pretty easy:
import AuthProvider extension ExampleUser: TokenAuthenticatable { // the token model that should be queried // to authenticate this user public typealias TokenType = ExampleToken }
Now that our example user is TokenAuthenticatable
, we can move on to the next step!
User Helper¶
Let's add a simple convenience method on request for accessing the authenticated user.
extension Request { func user() throws -> ExampleUser { return try auth.assertAuthenticated() } }
This is a nice shortcut that will come in handy in a few steps.
Middleware¶
To require authentication we need to add the TokenAuthenticationMiddleware
. You can apply this middleware
to individual routes or to the entire Droplet. For simplicity, we'll apply it to the Droplet.
import Vapor import AuthProvider import FluentProvider let config = try Config() config.preparations.append(ExampleUser.self) config.preparations.append(ExampleToken.self) let drop = try Droplet(config) let tokenMiddleware = TokenAuthenticationMiddleware(ExampleUser.self) /// use this route group for protected routes let authed = drop.grouped(tokenMiddleware)
Since our ExampleUser
class is TokenAuthenticatable
, we can pass it into the middleware's init method.
Seealso
If you only want to require authentication for certain routes, look at our Route Group section in the routing docs.
Route¶
Now that we have a route group protected by our TokenMiddleware, let's add a route to return the authenticated user's name.
authed.get("me") { req in // return the authenticated user's name return try req.user().name }
Tip
We're using the .user()
convenience we added to Request
here. It is a shortcut
for let user = try req.auth.assertAuthenticated(ExampleUser.self)
Database¶
That's it! We now have a functioning authentication system. Let's add a couple of entries to our database and test it out.
Users¶
id | name |
---|---|
1 | Bob |
Tokens¶
id | token | user_id |
---|---|---|
1 | foo | 1 |
Request¶
Now we can make a request to our Vapor app.
GET /me HTTP/1.1 Authorization: Bearer foo
And we should get a response like.
HTTP/1.1 200 OK Content-Type: text/plain Bob
Bad Token¶
To make sure it's secure, let's test using a token that's not in our database.
GET /me HTTP/1.1 Authorization: Bearer not-a-token
And we should get a response like.
HTTP/1.1 403 Forbidden
Next Steps¶
To build this out into a production-ready authentication system, you will need to build some additional routes for creating users and creating tokens.
Continue on in the Auth section to learn more about different types of authentication.