5
votes

I'm developing a simple web API with Vapor. To give more context, I'm newbie in backend development.

The consumer of the API is going to be an iOS app. Currently, I don't need the users to sign up to use the app. And I would like to keep it like that.

On the other hand, I would like to have some authentication to avoid that anyone could use the API I'm developing.

Looking for information I've found how implement authentication. But the examples I've seen are based on creating users in the backend for each user of the app. What I don't want to do. I would like to use an api-key as we do normally when we use third-party api's.

How could I have "api-key authentication" with Vapor ??

Or, should I just create an unique user/password that it's shared by all the users of the iOS app (that use the API) and then use basic or token authentication?

Thank you very much!

Carlos

2

2 Answers

5
votes

One way around this is to create a fake token and use either the TokenAuthenticationMiddleware or more likely a custom middleware that checks the incoming token.

However, be aware that there is nothing stopping anyone from inspecting the traffic coming from your app to view the token and then using that to access your API.

2
votes

Following Tim idea and an example from the book Server Side with Vapor (by the Raywenderlich.com Tutorial Team) I've created this custom middleware that makes the work:

final class SecretMiddleware: Middleware {

let secret: String

init(secret: String) {
    self.secret = secret
}

func respond(to request: Request, chainingTo next: Responder) throws -> Future<Response> {

    guard let bearerAuthorization = request.http.headers.bearerAuthorization else {
        throw Abort(.unauthorized, reason: "Missing token")
    }

    guard bearerAuthorization.token == secret else {
        throw Abort(.unauthorized, reason: "Wrong token")
    }

    return try next.respond(to: request)
}
}
extension SecretMiddleware: ServiceType {

static func makeService(for worker: Container) throws -> SecretMiddleware {

    let secret: String
    switch worker.environment {
    case .development:
        secret = "foo"
    default:
        guard let envSecret = Environment.get("SECRET") else {
            let reason = "No SECRET set on environment."
            throw Abort(.internalServerError, reason: reason)
        }
        secret = envSecret
    }
    return SecretMiddleware(secret: secret)
}
}