Triggered by this code
this is the code in Imperial/FederatedServiceRouter that throws:
` public func fetchToken(from request: Request) throws -> EventLoopFuture {
let code: String
if let queryCode: String = try request.query.get(at: codeKey) {
code = queryCode
} else if let error: String = try request.query.get(at: errorKey) {
throw Abort(.badRequest, reason: error)
} else {
throw Abort(.badRequest, reason: "Missing 'code' key in URL query")
}
let body = callbackBody(with: code)
let url = URI(string: accessTokenURL)
return body.encodeResponse(for: request)
.map { $0.body.buffer }
.flatMap { buffer in
return request.client.post(url, headers: self.callbackHeaders) { $0.body = buffer }
}.flatMapThrowing { response in
return try response.content.get(String.self, at: ["access_token"])
}
}`
Known issue people had already before:
Post here how sb fixed it
Alright. I think I figured it out...
What's the chance the data is being serialized as JSON even though I set static var defaultContentType: HTTPMediaType = .urlEncodedForm
in LinkedInCallbackBody
? The chance ended up being pretty high, given that adding a client.headers = HTTPHeaders(dictionaryLiteral: ("Content-Type", "application/x-www-form-urlencoded"))
to the beforeSend
closure eliminated the issue I was having.
That, or Vapor doesn't automatically set that header... which would make more sense.
public func fetchToken(from request: Request) throws -> EventLoopFuture<String> {
let code: String
if let queryCode: String = try request.query.get(at: "code") {
code = queryCode
} else if let error: String = try request.query.get(at: "error") {
throw Abort(.badRequest, reason: error)
} else {
throw Abort(.badRequest, reason: "Missing 'code' key in URL query")
}
let body = LinkedInCallbackBody(code: code, clientId: self.tokens.clientID, clientSecret: self.tokens.clientSecret, redirectURI: self.callbackURL)
let url = URI(string: self.accessTokenURL)
return body.encodeResponse(for: request).map {
$0.body
}.flatMap { body in
return request.client.post(url, beforeSend: { client in
client.body = body.buffer
client.headers = HTTPHeaders(dictionaryLiteral: ("Content-Type", "application/x-www-form-urlencoded"))
})
}.flatMapThrowing { response in
return try response.content.get(String.self, at: ["access_token"])
}
}
<@!432065887202181142> This is what the (working) method ended up being. I'm willing to share my Imperial+LinkedIn
code, if you think that'd be of any use.
I'm not quite good/confident enough with this to feel 100% comfortable submitting a PR, but maybe I should anyway...
public func fetchToken(from request: Request) throws -> EventLoopFuture<String> {
let code: String
if let queryCode: String = try request.query.get(at: "code") {
code = queryCode
} else if let error: String = try request.query.get(at: "error") {
throw Abort(.badRequest, reason: error)
} else {
throw Abort(.badRequest, reason: "Missing 'code' key in URL query")
}
let body = LinkedInCallbackBody(code: code, clientId: self.tokens.clientID, clientSecret: self.tokens.clientSecret, redirectURI: self.callbackURL)
let url = URI(string: self.accessTokenURL)
return body.encodeResponse(for: request).map {
$0.body
}.flatMap { body in
return request.client.post(url, beforeSend: { client in
client.body = body.buffer
client.headers = HTTPHeaders(dictionaryLiteral: ("Content-Type", "application/x-www-form-urlencoded"))
})
}.flatMapThrowing { response in
return try response.content.get(String.self, at: ["access_token"])
}
}
<@!432065887202181142> This is what the (working) method ended up being. I'm willing to share my Imperial+LinkedIn
code, if you think that'd be of any use.
I'm not quite good/confident enough with this to feel 100% comfortable submitting a PR, but maybe I should anyway...
public func fetchToken(from request: Request) throws -> EventLoopFuture<String> {
let code: String
if let queryCode: String = try request.query.get(at: "code") {
code = queryCode
} else if let error: String = try request.query.get(at: "error") {
throw Abort(.badRequest, reason: error)
} else {
throw Abort(.badRequest, reason: "Missing 'code' key in URL query")
}
let body = LinkedInCallbackBody(code: code, clientId: self.tokens.clientID, clientSecret: self.tokens.clientSecret, redirectURI: self.callbackURL)
let url = URI(string: self.accessTokenURL)
return body.encodeResponse(for: request).map {
$0.body
}.flatMap { body in
return request.client.post(url, beforeSend: { client in
client.body = body.buffer
client.headers = HTTPHeaders(dictionaryLiteral: ("Content-Type", "application/x-www-form-urlencoded"))
})
}.flatMapThrowing { response in
return try response.content.get(String.self, at: ["access_token"])
}
}
<@!432065887202181142> This is what the (working) method ended up being. I'm willing to share my Imperial+LinkedIn
code, if you think that'd be of any use.
I'm not quite good/confident enough with this to feel 100% comfortable submitting a PR, but maybe I should anyway...
I cannot fix this in the source code but as I saw other people are having the same issue, maybe this bug could be fixed.