@capgo/capacitor-social-login 0.0.50 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -347,7 +347,7 @@ Refresh the access token
347
347
 
348
348
  | Prop | Type |
349
349
  | -------------- | ---------------------------------------------------------------------------------------- |
350
- | **`facebook`** | <code>{ appId: string; }</code> |
350
+ | **`facebook`** | <code>{ appId: string; clientToken: string; }</code> |
351
351
  | **`google`** | <code>{ iOSClientId?: string; iOSServerClientId?: string; webClientId?: string; }</code> |
352
352
  | **`apple`** | <code>{ clientId?: string; redirectUrl?: string; }</code> |
353
353
 
@@ -30,7 +30,6 @@ public class FacebookProvider implements SocialProvider {
30
30
 
31
31
  private Activity activity;
32
32
  private CallbackManager callbackManager;
33
- private PluginCall savedCall;
34
33
 
35
34
  public FacebookProvider(Activity activity) {
36
35
  this.activity = activity;
@@ -76,7 +75,6 @@ public class FacebookProvider implements SocialProvider {
76
75
 
77
76
  @Override
78
77
  public void login(PluginCall call, JSONObject config) {
79
- this.savedCall = call;
80
78
  try {
81
79
  Collection<String> permissions = JsonHelper.jsonArrayToList(
82
80
  config.getJSONArray("permissions")
@@ -94,19 +92,19 @@ public class FacebookProvider implements SocialProvider {
94
92
  result.put("accessToken", createAccessTokenObject(accessToken));
95
93
  result.put("authenticationToken", loginResult.getAuthenticationToken() != null ? loginResult.getAuthenticationToken().getToken() : null);
96
94
  // TODO: Fetch profile information and add it to the result
97
- savedCall.resolve(result);
95
+ call.resolve(result);
98
96
  }
99
97
 
100
98
  @Override
101
99
  public void onCancel() {
102
100
  Log.d(LOG_TAG, "LoginManager.onCancel");
103
- savedCall.reject("Login cancelled");
101
+ call.reject("Login cancelled");
104
102
  }
105
103
 
106
104
  @Override
107
105
  public void onError(FacebookException exception) {
108
106
  Log.e(LOG_TAG, "LoginManager.onError", exception);
109
- savedCall.reject(exception.getMessage());
107
+ call.reject(exception.getMessage());
110
108
  }
111
109
  });
112
110
 
@@ -122,7 +120,7 @@ public class FacebookProvider implements SocialProvider {
122
120
  loginManager.logIn((ActivityResultRegistryOwner) activity, callbackManager, permissions);
123
121
  }
124
122
  } catch (JSONException e) {
125
- savedCall.reject("Invalid login options format");
123
+ call.reject("Invalid login options format");
126
124
  }
127
125
  }
128
126
 
package/dist/docs.json CHANGED
@@ -159,7 +159,7 @@
159
159
  "tags": [],
160
160
  "docs": "",
161
161
  "complexTypes": [],
162
- "type": "{ appId: string; } | undefined"
162
+ "type": "{ appId: string; clientToken: string; } | undefined"
163
163
  },
164
164
  {
165
165
  "name": "google",
@@ -4,6 +4,10 @@ export interface InitializeOptions {
4
4
  * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files
5
5
  */
6
6
  appId: string;
7
+ /**
8
+ * Facebook Client Token, provided by Facebook for web, in mobile it's set in the native files
9
+ */
10
+ clientToken: string;
7
11
  };
8
12
  google?: {
9
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSClientId?: string;\n /**\n * The app's server client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSServerClientId?: string;\n /**\n * The app's web client ID, found and created in the Google Developers Console.\n * For Android (and web in the future).\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n webClientId?: string;\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple for web and Android\n */\n clientId?: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl?: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n /**\n * Is Limited Login\n * @description use limited login for Facebook IOS\n * @default false\n */\n limitedLogin?: boolean;\n /**\n * Nonce\n * @description A custom nonce to use for the login request\n */\n nonce?: string;\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * Set if your application needs to refresh access tokens when the user is not present at the browser.\n * In response use `serverAuthCode` key\n *\n * @default false\n * @since 3.1.0\n * */\n grantOfflineAccess?: boolean;\n}\n\nexport interface GoogleLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n}\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description select scopes to login with\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n user: string | null;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n identityToken: string | null;\n authorizationCode: string | null;\n}\n\nexport interface LoginOptions {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Options\n * @description payload to login with\n */\n options: FacebookLoginOptions | GoogleLoginOptions | AppleProviderOptions;\n}\n\nexport interface LoginResult {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Payload\n * @description payload to login with\n */\n result: FacebookLoginResponse | GoogleLoginResponse | AppleProviderResponse;\n}\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n profile: {\n userID: string;\n email: string | null;\n friendIDs: string[];\n birthday: string | null;\n ageRange: { min?: number; max?: number } | null;\n gender: string | null;\n location: { id: string; name: string } | null;\n hometown: { id: string; name: string } | null;\n profileURL: string | null;\n name: string | null;\n imageURL: string | null;\n };\n authenticationToken: string | null;\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login(options: LoginOptions): Promise<LoginResult>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: \"apple\" | \"google\" | \"facebook\" }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(\n options: AuthorizationCodeOptions,\n ): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n /**\n * Facebook Client Token, provided by Facebook for web, in mobile it's set in the native files\n */\n clientToken: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSClientId?: string;\n /**\n * The app's server client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSServerClientId?: string;\n /**\n * The app's web client ID, found and created in the Google Developers Console.\n * For Android (and web in the future).\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n webClientId?: string;\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple for web and Android\n */\n clientId?: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl?: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n /**\n * Is Limited Login\n * @description use limited login for Facebook IOS\n * @default false\n */\n limitedLogin?: boolean;\n /**\n * Nonce\n * @description A custom nonce to use for the login request\n */\n nonce?: string;\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * Set if your application needs to refresh access tokens when the user is not present at the browser.\n * In response use `serverAuthCode` key\n *\n * @default false\n * @since 3.1.0\n * */\n grantOfflineAccess?: boolean;\n}\n\nexport interface GoogleLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n}\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description select scopes to login with\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n user: string | null;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n identityToken: string | null;\n authorizationCode: string | null;\n}\n\nexport interface LoginOptions {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Options\n * @description payload to login with\n */\n options: FacebookLoginOptions | GoogleLoginOptions | AppleProviderOptions;\n}\n\nexport interface LoginResult {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Payload\n * @description payload to login with\n */\n result: FacebookLoginResponse | GoogleLoginResponse | AppleProviderResponse;\n}\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n profile: {\n userID: string;\n email: string | null;\n friendIDs: string[];\n birthday: string | null;\n ageRange: { min?: number; max?: number } | null;\n gender: string | null;\n location: { id: string; name: string } | null;\n hometown: { id: string; name: string } | null;\n profileURL: string | null;\n name: string | null;\n imageURL: string | null;\n };\n authenticationToken: string | null;\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login(options: LoginOptions): Promise<LoginResult>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: \"apple\" | \"google\" | \"facebook\" }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(\n options: AuthorizationCodeOptions,\n ): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
@@ -2,9 +2,13 @@ import Foundation
2
2
  import AuthenticationServices
3
3
  import Alamofire
4
4
 
5
- struct AppleProviderResponse {
6
- // let user: String
5
+ struct AppleProviderResponse: Codable {
6
+ let user: String
7
+ let email: String?
8
+ let givenName: String?
9
+ let familyName: String?
7
10
  let identityToken: String
11
+ let authorizationCode: String
8
12
  }
9
13
 
10
14
  // Define the Decodable structs for the response
@@ -86,6 +90,7 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
86
90
  private let TOKEN_URL = "https://appleid.apple.com/auth/token"
87
91
  private let SHARED_PREFERENCE_NAME = "AppleProviderSharedPrefs_0eda2642"
88
92
  private var redirectUrl = ""
93
+ private let USER_INFO_KEY = "AppleUserInfo"
89
94
 
90
95
  func initialize(redirectUrl: String? = nil) {
91
96
  if let redirectUrl = redirectUrl {
@@ -199,21 +204,27 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
199
204
  }
200
205
 
201
206
  func getCurrentUser(completion: @escaping (Result<AppleProviderResponse?, Error>) -> Void) {
202
- let appleIDProvider = ASAuthorizationAppleIDProvider()
203
- appleIDProvider.getCredentialState(forUserID: "currentUserIdentifier") { (credentialState, error) in
204
- if let error = error {
205
- completion(.failure(error))
206
- return
207
- }
207
+ retrieveUserInfo { userInfo in
208
+ if let userInfo = userInfo {
209
+ completion(.success(userInfo))
210
+ } else {
211
+ let appleIDProvider = ASAuthorizationAppleIDProvider()
212
+ appleIDProvider.getCredentialState(forUserID: "currentUserIdentifier") { (credentialState, error) in
213
+ if let error = error {
214
+ completion(.failure(error))
215
+ return
216
+ }
208
217
 
209
- switch credentialState {
210
- case .authorized:
211
- // User is authorized, you might want to fetch more details here
212
- completion(.success(nil))
213
- case .revoked, .notFound, .transferred:
214
- completion(.success(nil))
215
- @unknown default:
216
- completion(.failure(NSError(domain: "AppleProvider", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unknown credential state"])))
218
+ switch credentialState {
219
+ case .authorized:
220
+ // User is authorized, but we don't have their info
221
+ completion(.success(nil))
222
+ case .revoked, .notFound, .transferred:
223
+ completion(.success(nil))
224
+ @unknown default:
225
+ completion(.failure(NSError(domain: "AppleProvider", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unknown credential state"])))
226
+ }
227
+ }
217
228
  }
218
229
  }
219
230
  }
@@ -227,52 +238,44 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
227
238
 
228
239
  func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
229
240
  if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
230
- let _ = appleIDCredential.user
241
+ let userIdentifier = appleIDCredential.user
231
242
  let fullName = appleIDCredential.fullName
232
243
  let email = appleIDCredential.email
233
244
 
234
- // let response = AppleProviderResponse(
235
- // user: userIdentifier,
236
- // email: email,
237
- // givenName: fullName?.givenName,
238
- // familyName: fullName?.familyName,
239
- // identityToken: String(data: appleIDCredential.identityToken ?? Data(), encoding: .utf8) ?? "",
240
- // authorizationCode: String(data: appleIDCredential.authorizationCode ?? Data(), encoding: .utf8) ?? ""
241
- // )
242
-
243
- let errorCompletion: ((Result<AppleProviderResponse, AppleProviderError>) -> Void) = { result in
244
- do {
245
- let finalResult = try result.get()
246
- self.completion?(.success(finalResult))
247
- } catch {
248
- self.completion?(.failure(error))
249
- }
250
- }
251
-
252
- let authorizationCode = String(data: appleIDCredential.authorizationCode ?? Data(), encoding: .utf8) ?? ""
253
- let identityToken = String(data: appleIDCredential.identityToken ?? Data(), encoding: .utf8) ?? ""
254
-
255
- if !self.redirectUrl.isEmpty {
256
- let firstName = fullName?.givenName ?? "Jhon"
257
- let lastName = fullName?.familyName ?? "Doe"
258
-
259
- if let _ = fullName?.givenName {
260
- sendRequest(code: authorizationCode, identityToken: identityToken, email: email ?? "", firstName: firstName, lastName: lastName, completion: errorCompletion, skipUser: false)
245
+ retrieveUserInfo { savedUserInfo in
246
+ let response = AppleProviderResponse(
247
+ user: userIdentifier,
248
+ email: email ?? savedUserInfo?.email,
249
+ givenName: fullName?.givenName ?? savedUserInfo?.givenName,
250
+ familyName: fullName?.familyName ?? savedUserInfo?.familyName,
251
+ identityToken: String(data: appleIDCredential.identityToken ?? Data(), encoding: .utf8) ?? "",
252
+ authorizationCode: String(data: appleIDCredential.authorizationCode ?? Data(), encoding: .utf8) ?? ""
253
+ )
254
+
255
+ // Persist user info
256
+ self.persistUserInfo(userInfo: response)
257
+
258
+ if !self.redirectUrl.isEmpty {
259
+ let firstName = fullName?.givenName ?? ""
260
+ let lastName = fullName?.familyName ?? ""
261
+
262
+ self.sendRequest(code: response.authorizationCode, identityToken: response.identityToken, email: email ?? "", firstName: firstName, lastName: lastName, completion: { result in
263
+ switch result {
264
+ case .success(let appleResponse):
265
+ self.completion?(.success(appleResponse))
266
+ case .failure(let error):
267
+ self.completion?(.failure(error))
268
+ }
269
+ }, skipUser: fullName?.givenName == nil)
261
270
  } else {
262
- sendRequest(code: authorizationCode, identityToken: identityToken, email: email ?? "", firstName: firstName, lastName: lastName, completion: errorCompletion, skipUser: true)
263
- }
264
- } else {
265
- do {
266
- try self.persistState(idToken: identityToken, refreshToken: "", accessToken: "")
267
- let appleResponse = AppleProviderResponse(identityToken: identityToken)
268
- completion?(.success(appleResponse))
269
- return
270
- } catch {
271
- completion?(.failure(AppleProviderError.specificJsonWritingError(error)))
272
- return
271
+ do {
272
+ try self.persistState(idToken: response.identityToken, refreshToken: "", accessToken: "")
273
+ self.completion?(.success(response))
274
+ } catch {
275
+ self.completion?(.failure(AppleProviderError.specificJsonWritingError(error)))
276
+ }
273
277
  }
274
278
  }
275
- // completion?(.success(response))
276
279
  }
277
280
  }
278
281
 
@@ -365,7 +368,14 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
365
368
 
366
369
  do {
367
370
  try self.persistState(idToken: idToken, refreshToken: refreshToken, accessToken: accessToken)
368
- let appleResponse = AppleProviderResponse(identityToken: idToken)
371
+ let appleResponse = AppleProviderResponse(
372
+ user: "", // We don't have this information at this point
373
+ email: nil, // We don't have this information at this point
374
+ givenName: nil, // We don't have this information at this point
375
+ familyName: nil, // We don't have this information at this point
376
+ identityToken: idToken,
377
+ authorizationCode: "" // We don't have this information at this point
378
+ )
369
379
  completion(.success(appleResponse))
370
380
  return
371
381
  } catch {
@@ -375,8 +385,14 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
375
385
  }
376
386
 
377
387
  if (pathComponents.filter { $0.name == "ios_no_code" }).first != nil {
378
- // identityToken provided by apple
379
- let appleResponse = AppleProviderResponse(identityToken: identityToken)
388
+ let appleResponse = AppleProviderResponse(
389
+ user: "", // You might want to extract this from the identityToken
390
+ email: email,
391
+ givenName: firstName,
392
+ familyName: lastName,
393
+ identityToken: identityToken,
394
+ authorizationCode: code
395
+ )
380
396
 
381
397
  do {
382
398
  try self.persistState(idToken: identityToken, refreshToken: "", accessToken: "")
@@ -470,7 +486,14 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
470
486
  let userData = try? JSONSerialization.jsonObject(with: decodedData, options: []) as? [String: Any],
471
487
  let userId = userData["sub"] as? String {
472
488
  // Create the response object
473
- let appleResponse = AppleProviderResponse(identityToken: idToken)
489
+ let appleResponse = AppleProviderResponse(
490
+ user: userId,
491
+ email: nil, // You might want to extract this from the idToken if available
492
+ givenName: nil,
493
+ familyName: nil,
494
+ identityToken: idToken,
495
+ authorizationCode: code
496
+ )
474
497
 
475
498
  // Log the tokens (replace with your logging mechanism)
476
499
  print("Apple Access Token is: \(accessToken)")
@@ -513,4 +536,25 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
513
536
  func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
514
537
  return UIApplication.shared.windows.first!
515
538
  }
539
+
540
+ func persistUserInfo(userInfo: AppleProviderResponse) {
541
+ let encoder = JSONEncoder()
542
+ if let encoded = try? encoder.encode(userInfo) {
543
+ UserDefaults.standard.set(encoded, forKey: USER_INFO_KEY)
544
+ print("Successfully saved user info locally")
545
+ }
546
+ }
547
+
548
+ func retrieveUserInfo(completion: @escaping (AppleProviderResponse?) -> Void) {
549
+ if let savedUserInfo = UserDefaults.standard.object(forKey: USER_INFO_KEY) as? Data {
550
+ let decoder = JSONDecoder()
551
+ if let loadedUserInfo = try? decoder.decode(AppleProviderResponse.self, from: savedUserInfo) {
552
+ completion(loadedUserInfo)
553
+ } else {
554
+ completion(nil)
555
+ }
556
+ } else {
557
+ completion(nil)
558
+ }
559
+ }
516
560
  }
@@ -52,10 +52,20 @@ class FacebookProvider {
52
52
  return
53
53
  }
54
54
 
55
- DispatchQueue.main.async {
55
+ DispatchQueue.main.async { [weak self] in
56
+ guard let self = self else { return }
57
+
58
+ // Check if a user is already logged in
59
+ if AccessToken.current != nil {
60
+ // User is already logged in, return current session info
61
+ let response = self.createLoginResponse()
62
+ completion(.success(response))
63
+ return
64
+ }
65
+
56
66
  self.loginManager.logIn(configuration: configuration) { result in
57
67
  switch result {
58
- case .success:
68
+ case .success(_, _, _):
59
69
  let response = self.createLoginResponse()
60
70
  completion(.success(response))
61
71
  case .failed(let error):
@@ -63,7 +73,6 @@ class FacebookProvider {
63
73
  case .cancelled:
64
74
  completion(.failure(NSError(domain: "FacebookProvider", code: 0, userInfo: [NSLocalizedDescriptionKey: "Login cancelled"])))
65
75
  }
66
-
67
76
  }
68
77
  }
69
78
  }
@@ -123,28 +132,32 @@ class FacebookProvider {
123
132
  }
124
133
 
125
134
  func logout(completion: @escaping (Result<Void, Error>) -> Void) {
126
- loginManager.logOut()
127
- completion(.success(()))
135
+ DispatchQueue.main.async { [weak self] in
136
+ self?.loginManager.logOut()
137
+ completion(.success(()))
138
+ }
128
139
  }
129
140
 
130
141
  func getCurrentUser(completion: @escaping (Result<[String: Any]?, Error>) -> Void) {
131
- if let accessToken = AccessToken.current {
132
- let response: [String: Any] = [
133
- "accessToken": [
134
- "applicationID": accessToken.appID,
135
- "declinedPermissions": accessToken.declinedPermissions.map { $0.name },
136
- "expirationDate": accessToken.expirationDate,
137
- "isExpired": accessToken.isExpired,
138
- "refreshDate": accessToken.refreshDate,
139
- "permissions": accessToken.permissions.map { $0.name },
140
- "tokenString": accessToken.tokenString,
141
- "userID": accessToken.userID
142
- ],
143
- "profile": [:]
144
- ]
145
- completion(.success(response))
146
- } else {
147
- completion(.success(nil))
142
+ DispatchQueue.main.async {
143
+ if let accessToken = AccessToken.current {
144
+ let response: [String: Any] = [
145
+ "accessToken": [
146
+ "applicationID": accessToken.appID,
147
+ "declinedPermissions": accessToken.declinedPermissions.map { $0.name },
148
+ "expirationDate": accessToken.expirationDate,
149
+ "isExpired": accessToken.isExpired,
150
+ "refreshDate": accessToken.refreshDate,
151
+ "permissions": accessToken.permissions.map { $0.name },
152
+ "tokenString": accessToken.tokenString,
153
+ "userID": accessToken.userID
154
+ ],
155
+ "profile": [:]
156
+ ]
157
+ completion(.success(response))
158
+ } else {
159
+ completion(.success(nil))
160
+ }
148
161
  }
149
162
  }
150
163
 
@@ -199,7 +199,23 @@ public class SocialLoginPlugin: CAPPlugin, CAPBridgedPlugin {
199
199
  }
200
200
  case "apple":
201
201
  apple.getCurrentUser { result in
202
- self.handleCurrentUserResult(result, call: call)
202
+ switch result {
203
+ case .success(let appleResponse):
204
+ if let response = appleResponse {
205
+ call.resolve([
206
+ "user": response.user,
207
+ "email": response.email ?? "",
208
+ "givenName": response.givenName ?? "",
209
+ "familyName": response.familyName ?? "",
210
+ "identityToken": response.identityToken,
211
+ "authorizationCode": response.authorizationCode
212
+ ])
213
+ } else {
214
+ call.resolve([:])
215
+ }
216
+ case .failure(let error):
217
+ call.reject(error.localizedDescription)
218
+ }
203
219
  }
204
220
  default:
205
221
  call.reject("Invalid provider")
@@ -280,10 +296,16 @@ public class SocialLoginPlugin: CAPPlugin, CAPBridgedPlugin {
280
296
  switch result {
281
297
  case .success(let response):
282
298
  if let appleResponse = response as? AppleProviderResponse {
299
+ // The user info is already persisted in the AppleProvider class
283
300
  call.resolve([
284
301
  "provider": "apple",
285
302
  "result": [
286
- "identityToken": appleResponse.identityToken
303
+ "user": appleResponse.user,
304
+ "email": appleResponse.email ?? "",
305
+ "givenName": appleResponse.givenName ?? "",
306
+ "familyName": appleResponse.familyName ?? "",
307
+ "identityToken": appleResponse.identityToken,
308
+ "authorizationCode": appleResponse.authorizationCode
287
309
  ]
288
310
  ])
289
311
  } else if let googleResponse = response as? GoogleLoginResponse {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-social-login",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "All social logins in one plugin",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",