@@ -43,6 +43,9 @@ public final class OpenGoogleSignIn: NSObject {
4343
4444 /// Google API OAuth 2.0 token url.
4545 private static let tokenURL : URL ? = URL ( string: " https://www.googleapis.com/oauth2/v4/token " )
46+
47+ /// Google API profile url
48+ private static let profileURL : URL ? = URL ( string: " https://www.googleapis.com/oauth2/v1/userinfo?alt=json " )
4649
4750 /// The client's redirect URI, which is based on `clientID`.
4851 private var redirectURI : String {
@@ -136,25 +139,64 @@ public final class OpenGoogleSignIn: NSObject {
136139
137140 /// Decodes `GoogleUser` from OAuth 2.0 response.
138141 private func decodeUser( from data: Data ) throws -> GoogleUser {
139- let decoder = JSONDecoder ( )
140- decoder. keyDecodingStrategy = . convertFromSnakeCase
141-
142- return try decoder. decode ( GoogleUser . self, from: data)
142+ try JSONDecoder . app. decode ( GoogleUser . self, from: data)
143143 }
144144
145145 /// Handles OAuth 2.0 token response.
146+ ///
147+ /// After successful authentication we made another request
148+ /// to obtain user's profile data, e.g. email and name.
146149 private func handleTokenResponse( using redirectUrl: URL , completion: @escaping ( Result < GoogleUser , GoogleSignInError > ) -> Void ) {
147- guard let code = self . parseCode ( from: redirectUrl) else {
150+ guard let code = parseCode ( from: redirectUrl) else {
148151 completion ( . failure( . invalidCode) )
149152 return
150153 }
151154
152155 guard let tokenRequest = makeTokenRequest ( with: code) else {
153- completion ( . failure( . invalidTokenRequest) )
156+ assertionFailure ( " Invalid token request " )
157+ return
158+ }
159+
160+ makeRequest ( tokenRequest) { result in
161+ switch result {
162+ case let . success( data) :
163+ do {
164+ let user = try self . decodeUser ( from: data)
165+ self . fetchProfile ( user: user, completion: completion)
166+ } catch {
167+ completion ( . failure( . tokenDecodingError( error) ) )
168+ }
169+
170+ case let . failure( error) :
171+ completion ( . failure( error) )
172+ }
173+ }
174+ }
175+
176+ private func fetchProfile( user: GoogleUser , completion: @escaping ( Result < GoogleUser , GoogleSignInError > ) -> Void ) {
177+ guard let profileRequest = makeProfileRequest ( user: user) else {
178+ assertionFailure ( " Invalid profile request " )
154179 return
155180 }
156181
157- let task = session. dataTask ( with: tokenRequest) { data, response, error in
182+ var user = user
183+
184+ makeRequest ( profileRequest) { result in
185+ switch result {
186+ case let . success( data) :
187+ let profile = try ? JSONDecoder . app. decode ( GoogleUser . Profile. self, from: data)
188+ user. profile = profile
189+ completion ( . success( user) )
190+
191+ case let . failure( error) :
192+ completion ( . failure( . noProfile( error) ) )
193+ }
194+ }
195+ }
196+
197+ /// Wrapper for easier `URLRequest` handling.
198+ private func makeRequest( _ request: URLRequest , completion: @escaping ( Result < Data , GoogleSignInError > ) -> Void ) {
199+ let task = session. dataTask ( with: request) { data, response, error in
158200 if let error = error {
159201 completion ( . failure( . networkError( error) ) )
160202 return
@@ -165,11 +207,7 @@ public final class OpenGoogleSignIn: NSObject {
165207 return
166208 }
167209
168- do {
169- completion ( . success( try self . decodeUser ( from: data) ) )
170- } catch {
171- completion ( . failure( . tokenDecodingError( error) ) )
172- }
210+ completion ( . success( data) )
173211 }
174212 task. resume ( )
175213 }
@@ -182,7 +220,7 @@ public final class OpenGoogleSignIn: NSObject {
182220 }
183221
184222 /// Returns `URLRequest` to retrieve Google sign-in OAuth 2.0 token using arameters provided by the app.
185- private func makeTokenRequest( with code: String ) -> URLRequest ? {
223+ func makeTokenRequest( with code: String ) -> URLRequest ? {
186224 guard let tokenURL = OpenGoogleSignIn . tokenURL else { return nil }
187225
188226 var request = URLRequest ( url: tokenURL)
@@ -205,6 +243,16 @@ public final class OpenGoogleSignIn: NSObject {
205243
206244 return request
207245 }
246+
247+ /// Returns `URLRequest` to retrieve user's profile data
248+ func makeProfileRequest( user: GoogleUser ) -> URLRequest ? {
249+ guard let profileURL = OpenGoogleSignIn . profileURL else { return nil }
250+
251+ var request = URLRequest ( url: profileURL)
252+ request. setValue ( " Bearer " + user. accessToken, forHTTPHeaderField: " Authorization " )
253+
254+ return request
255+ }
208256}
209257
210258// MARK: - ASWebAuthenticationPresentationContextProviding
0 commit comments