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

Add social authentication options including - Apple, Microsoft, Facebook, and Google #176

Conversation

eyatsenkoperpetio
Copy link
Contributor

@eyatsenkoperpetio eyatsenkoperpetio commented Nov 27, 2023

Add social authentication options including - Apple, Microsoft, Facebook, and Google

in config you need add:

SOCIAL_LOGINS:
ENABLED: true
APPLE_SIGNIN_ENABLED: true

MICROSOFT:
ENABLED: true
APP_ID: 'id'

GOOGLE:
ENABLED: true
GOOGLE_PLUS_KEY: 'id.apps.googleusercontent.com'
CLIENT_ID: 'id.apps.googleusercontent.com'

FACEBOOK:
ENABLED: true
FACEBOOK_APP_ID: 'id'
CLIENT_TOKEN: 'id'

@eyatsenkoperpetio
Copy link
Contributor Author

Screenshot 2023-11-27 at 16 05 51 Screenshot 2023-11-27 at 16 05 41

Copy link
Contributor

@mumer92 mumer92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we dont need following, if any social provider is enabled, it should work.

SOCIAL_LOGINS:
ENABLED: true

how about proving a Debug Preview for the SocialSignView?

import MSAL
import Swinject

enum Socials {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about renaming it to SocialAuthProvider or SocialIdentityProvider or IdentityProvider?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe SocialResult?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SocialAuthResult would seem more appropriate, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also how about moving this enum out to a separate file?

private func appleLogin(_ credentials: AppleCredentials) {
socialLogin(
externalToken: credentials.token,
backend: "apple-id",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the backend name to the new Socials enum?

}
socialLogin(
externalToken: currentAccessToken,
backend: "facebook",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the backend name to the new Socials enum?

private func googleLogin(_ gIDSignInResult: GIDSignInResult) {
socialLogin(
externalToken: gIDSignInResult.user.accessToken.tokenString,
backend: "google-oauth2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the backend name to the new Socials enum?

private func microsoftLogin(_ account: MSALAccount, _ token: String) {
socialLogin(
externalToken: token,
backend: "azuread-oauth2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the backend name to the new Socials enum?

LabelButton(
image: CoreAssets.iconFacebookWhite.swiftUIImage,
title: "\(title) \(AuthLocalization.facebook)",
backgroundColor: UIColor(red: 0.09, green: 0.46, blue: 0.95, alpha: 1.00).sui,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the color to Assets folder as we are using in the project?

LabelButton(
image: CoreAssets.iconMicrosoftWhite.swiftUIImage,
title: "\(title) \(AuthLocalization.microsoft)",
backgroundColor: UIColor(red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00).sui,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about moving the color to Assets folder as we are using in the project?

@@ -10,6 +10,8 @@ import Alamofire

enum AuthEndpoint: EndPointType {
case getAccessToken(username: String, password: String, clientId: String, tokenType: String)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this extra line.

Comment on lines 82 to 85
"client_id": clientId,
"token_type": "jwt",
"access_token": externalToken,
"asymmetric_jwt": true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we have a token_type coming from config, i think we should that value.

Comment on lines 68 to 84
ApplicationDelegate.shared.application(
app,
open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)

if GIDSignIn.sharedInstance.handle(url) {
return true
}

if MSALPublicClientApplication.handleMSALResponse(
url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String
) {
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should add check with the config, if a social auth is enabled, then handle the url, e.g.

if config.googleConfig.enabled {
        GIDSignIn.sharedInstance.handle(url)
}

@eyatsenkoperpetio
Copy link
Contributor Author

Screenshot 2023-11-28 at 12 24 18

added SocialSignView_Previews

@mumer92
Copy link
Contributor

mumer92 commented Nov 28, 2023

@eyatsenkoperpetio i see in config we have Apple under SOCIAL_LOGINS
like this

SOCIAL_LOGINS:
            ENABLED: true
            APPLE_SIGNIN_ENABLED: true

how about remove SOCIAL_LOGINS and make separate for Apple?
in this way we dont have to relay on SOCIAL_LOGINS dictionary.

Also can you update ConfigTests with the new dictionary and add test cases there?

@@ -145,6 +149,7 @@
071009CC28D1E24000344290 /* Presentation */ = {
isa = PBXGroup;
children = (
BA8B3A302AD5485100D25EF5 /* SocialSign */,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to SocialAuth because it's being used for both SignIn and Register? Thoughts?

import SwiftUI
import Core

struct SocialSignView: View {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to SocialAuthView because it's being used for both SignIn and Register? Thoughts?

}
}

final public class SocialSignViewModel: ObservableObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to SocialAuthViewModel because it's being used for both SignIn and Register? Thoughts?

@@ -8,6 +8,7 @@
import Foundation

public enum LoginMethod: String {
case apple = "Apple"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enum name is LoginMethod; I guess in this case, the methods are Password and SocialAuth. How about keeping two values and passing the social auth provider(Apple, Google, Facebook, etc) as a parameter to social auth?

}

@MainActor
func sign(with result: Result<SocialResult, Error>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please give it a descriptive name? it's hard to understand the functionality of the function by looking at the name.

Comment on lines 46 to 47
case .socialLogin:
return .post
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using an OR case condition with getAccessToken?


import SwiftUI

public struct LabelButton: View {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename it to SocailAuthButton because we can't say we can generalize this button style for other parts of the app?

Comment on lines +37 to +52
"GOOGLE": [
"ENABLED": true,
"CLIENT_ID": "clientId"
],
"FACEBOOK": [
"ENABLED": true,
"FACEBOOK_APP_ID": "facebookAppId",
"CLIENT_TOKEN": "client_token"
],
"MICROSOFT": [
"ENABLED": true,
"APP_ID": "appId"
],
"APPLE_SIGNIN": [
"ENABLED": true
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add tests for these values as well?

FirebaseApp.configure(options: configuration)
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
if let config = Container.shared.resolve(ConfigProtocol.self) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra new line.

let familyName = credentials.fullName?.familyName ?? storage?.appleSignFamilyName ?? ""

let email = credentials.email ?? storage?.appleSignEmail ?? ""
var name: String = "\(givenName) \(familyName)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just save the formatted name instead of saving separately saving family and given name?

@saeedbashir
Copy link
Contributor

saeedbashir commented Dec 6, 2023

@eyatsenkoperpetio Tests are also failing. Please take a look into it. And the email is empty in case of Register with Apple on subsequent request if account not registered on first try.

}

@MainActor
func sign(with result: Result<SocialAuthDetails, Error>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to login(with .....)

}

@MainActor
private func social(result: SocialAuthDetails) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to socialAuth(result....)

@StateObject var viewModel: SocialAuthViewModel

init(
signType: SocialAuthType = .signIn,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to authType?

Comment on lines 17 to 20
case apple(AppleCredentials)
case facebook(LoginManagerLoginResult)
case google(GIDSignInResult)
case microsoft(MSALAccount, String)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please create a new struct like below and use it for all social auth providers? It will generalize the code for all social auth providers.

struct SocialAuthResponse {
    var name: String
    var email: String
    var token: String
}

like

case apple(SocialAuthResponse)
case facebook(SocialAuthResponse)
..


"FORGOT.TITLE"= "Forgot password";
"FORGOT.DESCRIPTION" = "Please enter your log-in or recovery email address below and we will send you an email with instructions.";
"FORGOT.REQUEST" = "Reset password";
"FORGOT.CHECK_TITLE" = "Check your email";
"FORGOT.CHECK_Description" = "We have sent a password recover instructions to your email ";


"SIGN_IN_WITH" = "Sign in with";
"SIGN_IN_REGISTER" = "Register with";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to REGISTER_WITH?

"ERROR.INVALID_EMAIL_ADDRESS_OR_USERNAME" = "Invalid email or username";
"ERROR.INVALID_PASSWORD_LENGTH" = "Invalid password length";
"ERROR.ACCOUNT_DISABLED" = "Your account is disabled. Please contact customer support for assistance.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it's fine but ERROR.DISABLED_ACCOUNT sounds good.

@@ -10,6 +10,7 @@ import Alamofire

enum AuthEndpoint: EndPointType {
case getAccessToken(username: String, password: String, clientId: String, tokenType: String)
case getEchangeAccessToken(externalToken: String, backend: String, clientId: String, tokenType: String)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to exchangeAccessToken?

storage?.appleSignFullName = name
}

if storage?.appleSignEmail == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of storage?.appleSignEmail is an empty string so the email is not being saved into storage for later ussage.

@@ -0,0 +1,63 @@
//
// FacebookSingInProvider.swift
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please change these names as well after renaming the files? You might need to make this change in all the relevant files like SocialAuthView, SocialAuthViewModel etc.

@@ -0,0 +1,74 @@
//
// LabelButton.swift
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this as well

Copy link
Contributor

@saeedbashir saeedbashir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Let the test cases pass.

@volodymyr-chekyrta volodymyr-chekyrta merged commit 739233e into openedx:develop Dec 7, 2023
3 checks passed
@forgotvas forgotvas deleted the 103-social-login-and-authentication-mobileios branch June 20, 2024 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[iOS] Social Login and Authentication
5 participants