Sign in with apple missing App Name in the permission message - ios

I am trying to Sign in with Apple using Auth0.
But the permission message shows my app name as null
This is the permission message.
Do you want to sign in to null with you Apple ID "myAppleId#email.com"?
The logo of my app is showing correctly. It is the app name that is showing null
Where do I set the app name?
Edit: Here is how it looks -

You need to set the name and email while sending the request as requestedscopes.
Function to create a request using ASAuthorizationAppleIDProvider and initialize a controller ASAuthorizationController to perform the request.
#objc func handleAppleIdRequest() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = selfauthorizationController.performRequests()
}
Below function is called after successful Sign In.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
print(“User id is \(userIdentifier) \n Full Name is \(String(describing: fullName)) \n Email id is \(String(describing: email))”) }}

If trying with Auth0, you can go with the following way to solve this problem.
Step 1.
if #available(iOS 13.0, *) {
// Create the authorization request
let request = ASAuthorizationAppleIDProvider().createRequest()
// Set scopes
request.requestedScopes = [.email, .fullName]
// Setup a controller to display the authorization flow
let controller = ASAuthorizationController(authorizationRequests: [request])
// Set delegates to handle the flow response.
controller.delegate = self
controller.presentationContextProvider = self
// Action
controller.performRequests()
}
Step 2
Implement the delegate method and get apple's authorization code there.
extension ViewController: ASAuthorizationControllerDelegate {
#available(iOS 13.0, *)
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
// Success
guard let authorizationCode = appleIDCredential.authorizationCode,
let authCode = String(data: authorizationCode, encoding: .utf8) else {
print("Problem with the authorizationCode")
return
}
}
}
}
Step 3
Now you use this authCode to login to the Auth0.
func appleSignin(with authCode: String) {
Auth0.authentication().tokenExchange(withAppleAuthorizationCode: authCode)
.start { result in
switch result {
case .success(let credentials):
//LoginSucces
case .failure(let error):
//Issue with login.
}
}
}
In this method, you don't show the webview like for other login methods with Auth0.
I had posted this on Auth0 Community (the issue that I posted here), and one of their engineers replied me to approach it this way.
Check this out for more info Sign in with Apple - Auth0

In my case, the reason was an incorrectly pointed federated sign in domain, and the solution provided didnt work for me, so here is my solution:
Go to developer.apple.com
Navigate to "Certificates, Identifiers, & Profiles"
Select "Identifiers" from the left sidebar
Select "Services IDs" from the right drop down box
Select "Configure" for "sign in with apple"
Add the correct Cognito domain name under the website URLs section
The name that will show up for "null" is whatever the name of the services ID is now

I am not using Auth0 but I was facing this issue and it took me an hour to find out where that thing is set!
It was showing a dummy string I had put once, a long time ago. Now I wanted to replace it but couldn't find out whether that was in the app, code, build script, app setting, developer settings, or where the hell!
I wanted to change this:
It turned out that when you go to Certificates, Identifiers & Profiles (at https://developer.apple.com/account/resources/identifiers/list) you can actually click on that blue thing on the top right of IDentifiers and that's bringing a whole list of things!
Why the hell Apple thought that putting a sub-menu over there is better than having a nested list in the left menu bar is beyond my imagination!
So from here, you go to Service IDs and change that thingy! If it's null and you can set it. The direct link to that Shangri-la page is: https://developer.apple.com/account/resources/identifiers/list/serviceId

Related

Converting switch-as from Switch to Objective-C

My question is regarding this sample code from Apple.
How do I convert this switch statement using the as keyword to an Objective-C equivalent? I'm just interested in the case statements.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
// Create an account in your system.
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
// For the purpose of this demo app, store the `userIdentifier` in the keychain.
self.saveUserInKeychain(userIdentifier)
// For the purpose of this demo app, show the Apple ID credential information in the `ResultViewController`.
self.showResultViewController(userIdentifier: userIdentifier, fullName: fullName, email: email)
case let passwordCredential as ASPasswordCredential:
// Sign in using an existing iCloud Keychain credential.
let username = passwordCredential.user
let password = passwordCredential.password
// For the purpose of this demo app, show the password credential as an alert.
DispatchQueue.main.async {
self.showPasswordCredentialAlert(username: username, password: password)
}
default:
break
}
}
In ObjC, the equivalent of this kind of as is -isKindOfClass:. You'll need to use if statements, since there's no equivalent version of switch. It would be something along these lines:
id<ASAuthorizationCredential> credential = authorization.credential;
if ([credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *appleIDCredential = (ASAuthorizationAppleIDCredential *)credential;
// ...
}
else if ([credential isKindOfClass:[ASPasswordCredential class]]) {
ASPasswordCredential *passwordCredential = (ASPasswordCredential *)credential;
// ...
}
ObjC has two class-checking methods, -isKindOfClass: and -isMemberOfClass:. The "kind" version checks for the given class and all subclasses. The "member" version checks the exact class, so it can differentiate between superclasses and their subclasses if needed.

I am getting Email and FullName as nil values when I am trying to SignIn with Apple

I have implemented Apple SignIn in one of my application. But when user selects hide my email, then i am getting Email and FullName as nil values. Can anyone please help me on this?
If the user select hide my email then the value of email will nil. No way to get the email.
For the first time authentication, you can get the user fullName. But in second-time authentication, the value of fullName will be nil.
For more you can check this: ASAuthorizationAppleIDRequest with name and mail scope returns nil values
Did you aware of defining request scopes while you were performing request?
Your code should be some how similar to this:
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.performRequests()
And when you receive the response, after converting it to ASAuthorizationAppleIDCredential, You can see fullname and email address by printing them out :
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
debugPrint(appleIDCredential.email) //prints either 'email' or 'proxied email'
debugPrint(appleIDCredential.fullName) //prints name 'object'
default:
break
}
}
Edit:
If problem persists, go to settings -> profile -> password and security -> apps using your apple id
find your app and revoke its access and try again!

Basecamp3 login issue with Oauth2 in Swift

My app needs to get a basecamp3 login. Hence I used the OAuth2Swift library. But unfortunately, I am unable to receive the token from basecamp even the user has authorized the app.
Below is the screenshot
I have used the following code
func createAuthRequest(){
// create an instance and retain it
let oauthswift = OAuth2Swift(
consumerKey: clientID,
consumerSecret: clientSecret,
authorizeUrl: authURL,
responseType: "token"
)
//oauthswift.authorizeURLHandler = self
oauthswift.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oauthswift)
let handle = oauthswift.authorize(
withCallbackURL: URL(string: redirectURL)!,
scope: "profile", state:"") { result in //This block of code never executed
switch result {
case .success(let (credential, response, parameters)):
print(credential.oauthToken)
// Do your request
case .failure(let error):
print(error.localizedDescription)
}
}
}
The code inside withCallbackURL never executed even the user has authorized the app.
Any help regarding this is appreciated.
I found the solution the problem was I was using wrong authentication & token URL.
Following URL need to be used. I missed to add web_server in auth/token url and unfortunately Basecamp haven't mentioned the same in their documets.
let authURL = "https://launchpad.37signals.com/authorization/new?type=web_server"
let tokenURL = "https://launchpad.37signals.com/authorization/token?type=web_server"
and redirectURL = com.abc.abc:/oauth2Callback (The same redircturl need to be updated for app under basecamp developer console where com.abc.abc is bundle id of the app)

Athentication problems on iOS when using AppAuth and Okta

I have a simple iOS Swift app loosely based on the AppAuth-iOS example (https://github.com/openid/AppAuth-iOS) as well as Okta OAuth sample (https://github.com/oktadeveloper/okta-openidconnect-appauth-ios). I am not using Service Discovery nor authomatic token aquisition (i.e. not using authStateByPresentingAuthorizationRequest).
My sample works against Azure AD but does not work against Okta. I am able to log in and am authenticated and redirected back to my mobile app (AppDelegate.application()) but then the flow does not return to my OIDAuthorizationService.present() completion block.
Here is some code:
#IBAction func signInButton(_ sender: Any) {
// select idp
switch selectedIdentityProvider! {
case "Azure AD":
selectedAuthConfig = AzureAdAuthConfig()
case "Okta":
selectedAuthConfig = OktaAuthConfig();
default:
return
}
appAuthAuthorize(authConfig: selectedAuthConfig!)
}
func appAuthAuthorize(authConfig: AuthConfig) {
let serviceConfiguration = OIDServiceConfiguration(
authorizationEndpoint: NSURL(string: authConfig.authEndPoint)! as URL,
tokenEndpoint: NSURL(string: authConfig.tokenEndPoint)! as URL)
let request = OIDAuthorizationRequest(configuration: serviceConfiguration, clientId: authConfig.clientId, scopes: authConfig.scope, redirectURL: NSURL(string: authConfig.redirectUri)! as URL, responseType: OIDResponseTypeCode, additionalParameters: nil)
doAppAuthAuthorization(authRequest: request)
}
func doAppAuthAuthorization(authRequest: OIDAuthorizationRequest) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.currentAuthorizationFlow = OIDAuthorizationService.present(authRequest, presenting: self, callback: {
(authorizationResponse, error) in
if (authorizationResponse != nil) {
self.authState = OIDAuthState(authorizationResponse: authorizationResponse!)
self.logMessage(message: "Got authorization tokens. Access token: \(String(describing: self.authState?.lastAuthorizationResponse.authorizationCode))")
self.doTokenRequest()
} else {
self.authState = nil
self.logMessage(message: "Authorization error: \(String(describing: error?.localizedDescription))")
}
})
}
I could rewrite the code to use authStateByPresentingAuthorizationRequest() to see if it works but am a bit leery as this code works against Azure AD. Any suggestions?
Update 1
I forgot to mention that I have a working Android/Java example going against the same Okta definitions and working like a charm.
Update 2
I did rewrite the code to use authStateByPresentingAuthorizationRequest() against Okta and am getting the same result (i.e. getting stuck after redirect back to my app). I tested this against Azure AD and it works Ok.
Resolved. I guess the problem was that the redirect URL defined in Okta was mixed case. Android AppAuth implementation does not mind but iOS AppAuth implementation does. Changed redirect URL in Okta to lower case only, changed redirect Uri paramter passed in to lower case only and bing, all works great. Thanks #jmelberg for pointing me in this direction - by debugging resumeAuthorizationFlow(with: url) I was able to see the exact behaviour and why the call returned a False.

Authenticating with OAuth2 on iOS

I am currently trying to authorize my users with OAuth2. I am currently using the following library: https://github.com/p2/OAuth2
let oauth2 = OAuth2CodeGrant(settings: [
"client_id": "my-id",
"authorize_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://www.googleapis.com/oauth2/v3/token",
"scope": "profile", // depends on the API you use
"redirect_uris": ["com.TestAuthorizeApp:/oauth2Callback"],
])
//let oauth2 = OAuth2CodeGrant(settings: settings)
oauth2.onAuthorize = { parameters in
print("Did authorize with parameters: \(parameters)")
}
oauth2.onFailure = { error in // `error` is nil on cancel
if let error = error {
print("Authorization went wrong: \(error)")
}
}
oauth2.authConfig.authorizeEmbedded = false
oauth2.authorize()
When I run this it loads up google in the browser and I am able to sign in. It then asks me about the permissions I have declared in the scope and that works fine. I click ok open and it redirects me back to my app.
However when I run this code again I am expecting that the access token has been stored in the key chain. However this doesn't seem to be working.
I have looked inside the source code and found the following check: tryToObtainAccessTokenIfNeeded which always returns false. This means I get the page again where I need to click 'Allow'.
I was wondering if someone could help me figure out why it's not saving anything in the keychain. Also does this mean the user is not really being authenticated?
Thanks.
===
Edit
Have added oauth2.verbose = true as per Pascal's comment. I get the following output.
OAuth2: Looking for items in keychain
OAuth2: No access token, maybe I can refresh
OAuth2: I don't have a refresh token, not trying to refresh
Which is what I thought was happening. However I am still unsure as to why it's not saving / finding anything in the keychain.
=====
Edit 2
It turns out that I wasn't actually getting an access token back at all. Please see this conversation: https://github.com/p2/OAuth2/issues/109 and my answer below.
With the help from Pascal here: https://github.com/p2/OAuth2/issues/109 I have managed to get it working. Turns out that I wasn't implementing step: '3 Authorize the User' as I should have been.
So a complete solution is:
Inside my view controller I have the following:
let OAuth2AppDidReceiveCallbackNotification = "OAuth2AppDidReceiveCallback"
override func viewDidLoad() {
super.viewDidLoad()
// This notification is for handling step 3 in guide.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.handleRedirect(_:)), name: OAuth2AppDidReceiveCallbackNotification, object: nil)
}
func authoriseUser {
let oauth2 = OAuth2CodeGrant(settings: [
"client_id": "my-id", // Use own client_id here
"authorize_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://www.googleapis.com/oauth2/v3/token",
"scope": "profile", // depends on the API you use
"redirect_uris": ["com.TestAuthorizeApp:/oauth2Callback"],
])
//let oauth2 = OAuth2CodeGrant(settings: settings)
oauth2.onAuthorize = { parameters in
print("Did authorize with parameters: \(parameters)")
}
oauth2.onFailure = { error in // `error` is nil on cancel
if let error = error {
print("Authorization went wrong: \(error)")
}
}
oauth2.authConfig.authorizeEmbedded = false
oauth2.authorize()
}
// This method gets called by notification and is the last thing we need to do to get our access token.
func handleRedirect(notification: NSNotification) {
oauth2.handleRedirectURL(notification.object as! NSURL)
}
The above code should handle sending you to the google web page where you can log in and then click allow.
Now you need to handle returning to the app in the app delegate:
let OAuth2AppDidReceiveCallbackNotification = "OAuth2AppDidReceiveCallback"
func application(application: UIApplication,
openURL url: NSURL,
sourceApplication: String?,
annotation: AnyObject) -> Bool {
// you should probably first check if this is your URL being opened
NSNotificationCenter.defaultCenter().postNotificationName(OAuth2AppDidReceiveCallbackNotification, object: url)
return true
}
Hopefully this will help anyone else who might be having issues trying to get an access token.

Resources