I am getting the following error at the final Run in the chapter.
{"error":true,"reason":"Value required for key 'access_token'."}
I tried everything I could think of in my own code. Then I loaded up the starter project for chapter 23, and got the same results…
Not sure what else to try on this one? I did a swift package update and then a vapor build. Using latest greatest public Xcode version.
0xtim
April 11, 2019, 12:04pm
2
@viper827 what request/point in the login with Google flow are you getting that error? I’ve just tried with GitHub - raywenderlich/vapor-til: The TIL Application for the Vapor book and it works
So it lets me click the button, I get taken to the google page to pick the account I wish to use, and then once it redirects me back to my page I get the error.
0xtim
April 12, 2019, 2:28pm
4
Can you show your ImperialController.swift? It’s like something is out of whack, especially as I can’t reproduce it
import Vapor
import Imperial
import Authentication
struct ImperialController: RouteCollection {
func boot(router: Router) throws {
guard let googleCallbackURL = Environment.get("GOOGLE_CALLBACK_URL") else {
fatalError("Callback URL not set")
}
try router.oAuth(from: Google.self, authenticate: "login-google", callback: googleCallbackURL,
scope: ["profile", "email"], completion: processGoogleLogin)
}
func processGoogleLogin(request: Request, token: String) throws -> Future<ResponseEncodable> {
return try Google.getUser(on: request).flatMap(to: ResponseEncodable.self) { userInfo in
return User.query(on: request).filter(\.username == userInfo.email)
.first().flatMap(to: ResponseEncodable.self) { foundUser in
guard let existingUser = foundUser else {
let user = User(name: userInfo.name, username: userInfo.email, password: UUID().uuidString)
return user.save(on: request).map(to: ResponseEncodable.self) { user in
try request.authenticateSession(user)
return request.redirect(to: "/")
}
}
try request.authenticateSession(existingUser)
return request.future(request.redirect(to: "/"))
}
}
}
}
struct GoogleUserInfo: Content {
let email: String
let name: String
}
extension Google {
static func getUser(on request: Request) throws -> Future<GoogleUserInfo> {
var headers = HTTPHeaders()
headers.bearerAuthorization = try BearerAuthorization(token: request.accessToken())
let googleAPIURL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
return try request.client().get(googleAPIURL, headers: headers).map(to: GoogleUserInfo.self) { response in
guard response.http.status == .ok else {
if response.http.status == .unauthorized {
throw Abort.redirect(to: "/login-google")
} else {
throw Abort(.internalServerError)
}
}
return try response.content.syncDecode(GoogleUserInfo.self)
}
}
}
I’m using the completed file that provided with the book.
0xtim
April 18, 2019, 3:36pm
7
@viper827 if you breakpoint I’m assuming it’s not hitting your code and is failing inside Imeperial? Does it work if you try with the whole Vapor TIL project from GH?
@viper827 Do you still have issues with this?
mynona
March 30, 2022, 7:39pm
9
I have exactly the same problem:
In Imperial this error is triggered:
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"])
}
}
mynona
March 30, 2022, 7:40pm
10
I also use exactly the same code from the book:
import ImperialGoogle
import Vapor
import Fluent
struct ImperialRouter: RouteCollection {
func boot(routes: RoutesBuilder) throws {
guard let googleCallbackURL = Environment.get("GOOGLE_CALLBACK_URL")
else { fatalError("Google callback URL not set") }
try routes.oAuth(from: Google.self,
authenticate: "login-google",
callback: googleCallbackURL,
scope: ["profile", "email"],
completion: processGoogleLogin
)
}
func processGoogleLogin(request: Request, token: String) throws → EventLoopFuture {
try Google
.getUser(on: request)
.flatMap { userInfo in
Author
.query(on: request.db)
.filter(\.$username == userInfo.email)
.first()
.flatMap { foundUser in
guard let existingUser = foundUser
else {
let user = Author(first_name: "",
last_name: userInfo.name,
username: userInfo.email,
password: UUID().uuidString,
role: .VIEWER
)
return user
.save(on: request.db)
.map {
request.session.authenticate(user)
return request.redirect(to: "/")
}
}
request.session.authenticate(existingUser)
return request.eventLoop.future(request.redirect(to: "/"))
}
}
}
}
struct GoogleUserInfo: Content {
let email: String
let name: String
}
extension Google {
static func getUser(on request: Request) throws → EventLoopFuture {
var headers = HTTPHeaders()
headers.bearerAuthorization = try BearerAuthorization(token: request.accessToken())
let googleAPIURL: URI = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
return request.client.get(googleAPIURL, headers: headers).flatMapThrowing { response in
guard response.status == .ok
else { if response.status == .unauthorized {
throw Abort.redirect(to: "/login-google")
} else { throw Abort(.internalServerError) }
}
return try response.content.decode(GoogleUserInfo.self)
}
}
}
mynona
March 30, 2022, 7:41pm
11
This is the error message:
(Postet it also on discord but then I saw that other people had exactly the same issue. Therefore I added it here in case somebody could solve this issue already.)
hshere
July 1, 2022, 12:22am
12
This error happens on the iOS client when the server is not running. Once I re-ran the server (which I thought was running, but stopped working after my machine was slept and un slept several times) it all started working again.