Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google OAuth fixes #107

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Sources/ImperialCore/Routing/FederatedServiceRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ extension FederatedServiceRouter {
.flatMap { buffer in
return request.client.post(url, headers: self.callbackHeaders) { $0.body = buffer }
}.flatMapThrowing { response in
if let refreshToken = try? response.content.get(String.self, at: ["refresh_token"]), !refreshToken.isEmpty {
request.session.setRefreshToken(refreshToken)
}
return try response.content.get(String.self, at: ["access_token"])
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ImperialGoogle/Standard/Google.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Google: FederatedService {
scope: [String] = [],
completion: @escaping (Request, String) throws -> (EventLoopFuture<ResponseEncodable>)
) throws {
self.router = try GoogleRouter(callback: callback, completion: completion)
self.router = try GoogleRouter(callback: callback, completion: completion, accessType: .online)
self.tokens = self.router.tokens

self.router.scope = scope
Expand Down
4 changes: 4 additions & 0 deletions Sources/ImperialGoogle/Standard/GoogleAccessType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public enum GoogleAccessType: String {
case offline = "offline"
case online = "online"
}
25 changes: 25 additions & 0 deletions Sources/ImperialGoogle/Standard/GoogleOffline.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@_exported import ImperialCore
import Vapor

public class GoogleOffline: FederatedService {
public var tokens: FederatedServiceTokens
public var router: FederatedServiceRouter

@discardableResult
public required init(
routes: RoutesBuilder,
authenticate: String,
authenticateCallback: ((Request) throws -> (EventLoopFuture<Void>))?,
callback: String,
scope: [String] = [],
completion: @escaping (Request, String) throws -> (EventLoopFuture<ResponseEncodable>)
) throws {
self.router = try GoogleRouter(callback: callback, completion: completion, accessType: .offline)
self.tokens = self.router.tokens

self.router.scope = scope
try self.router.configureRoutes(withAuthURL: authenticate, authenticateCallback: authenticateCallback, on: routes)

OAuthService.register(.google)
}
}
27 changes: 25 additions & 2 deletions Sources/ImperialGoogle/Standard/GoogleRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class GoogleRouter: FederatedServiceRouter {
public let callbackURL: String
public let accessTokenURL: String = "https://www.googleapis.com/oauth2/v4/token"
public let service: OAuthService = .google
public var accessType: GoogleAccessType = .online
public let callbackHeaders: HTTPHeaders = {
var headers = HTTPHeaders()
headers.contentType = .urlEncodedForm
Expand All @@ -19,18 +20,32 @@ public class GoogleRouter: FederatedServiceRouter {
self.callbackURL = callback
self.callbackCompletion = completion
}

public convenience init(
callback: String,
completion: @escaping (Request, String) throws -> (EventLoopFuture<ResponseEncodable>),
accessType: GoogleAccessType
) throws {
try self.init(callback: callback, completion: completion)
self.accessType = accessType
}

public func authURL(_ request: Request) throws -> String {
var components = URLComponents()
components.scheme = "https"
components.host = "accounts.google.com"
components.path = "/o/oauth2/auth"
components.path = "/o/oauth2/v2/auth"
components.queryItems = [
clientIDItem,
redirectURIItem,
scopeItem,
codeResponseTypeItem
codeResponseTypeItem,
accessTypeItem
]

if accessType == .offline {
components.queryItems?.append(promptItem)
}

guard let url = components.url else {
throw Abort(.internalServerError)
Expand All @@ -46,4 +61,12 @@ public class GoogleRouter: FederatedServiceRouter {
redirectURI: callbackURL)
}

public var accessTypeItem: URLQueryItem {
.init(name: "access_type", value: accessType.rawValue)
}

public var promptItem: URLQueryItem {
.init(name: "prompt", value: "consent")
}

}