Connecting to the Secure Content in IOS - ios

I am trying to connect to the portal object with the authenticated user which is cached and used throughout the app session, to provide the app with a view of a portal that is centered around a single user.
When the app is restarted, the credential must be reinstated, or the user must repeat the authentication process.
But every time when I connect it asks for username and password, I actually want to embed that into the code.
Any workarounds?
Below is my code.
self.portal = AGSPortal(url: URL(string: "https://www.arcgis.com")!, loginRequired: false)
self.portal.credential = AGSCredential(user: "theUser", password: "thePassword")
self.portal.load() {[weak self] (error) in
if let error = error {
print(error)
return
}
if self?.portal.loadStatus == AGSLoadStatus.loaded {
let fullName = self?.portal.user?.fullName
print(fullName!)
}
}

You can use AGSCredentialCache's enableAutoSyncToKeychainWithIdentifier:accessGroup:acrossDevices:accessible: to store credentials in the Keychain and when you re-launch the app, it won't prompt again. Please call this function at the start of the application using AGSAuthenticationManager.shared().credentialCache.
Regards,
Nimesh

Related

AWS Amplify iOS SDK : FederatedSignIn Failed to retrieve authorization token on Amplify.API.post

I've been working with the Amplify SDK to get federatedSignIn working with my iOS app with "Sign in with Apple" and Cognito to eventually make calls to API Gateway / Lambda functions.
TL;DR : My access token does not appear to be "automatically included in outbound requests" to my API as per the last paragraph of this section of the docs : Cognito User pool authorization
I have successfully authenticated using the tutorial found here Authentication Getting Started and other various Youtube videos on the Amazon Web Services channel.
Upon successful sign in through Apple I'm given an ASAuthorizationAppleIDCredential object. This contains the user field (token) which I pass to the Amplify.Auth class using the following Swift code :
func signIn (with userId: String)
{
guard
let plugin = try? Amplify.Auth.getPlugin(for: AWSCognitoAuthPlugin().key),
let authPlugin = plugin as? AWSCognitoAuthPlugin,
case .awsMobileClient (let client) = authPlugin.getEscapeHatch()
else
{
return
}
client.federatedSignIn(providerName: AuthProvider.signInWithApple.rawValue, token: userId) { (state, error) in
if let unwrappedError = error
{
print (unwrappedError)
}
else if let unwrappedState = state
{
print ("Successful federated sign in:", unwrappedState)
}
}
}
All appears to be successful and to double check I use the following bit of code to ensure I'm authorized :
func getCredentialsState (for userId:String)
{
let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: userId) { (credentialsState, error) in
if let unwrappedError = error
{
print (unwrappedError)
}
switch credentialsState
{
case .authorized:
print ("User Authorized")
case .notFound, .revoked:
print ("User Unauthenticated")
case .transferred:
print ("User Needs Transfer")
#unknown default:
print ("User Handle new use cases")
}
}
}
In the console I see "User Authorized" so everything appears to be working well.
However when I then go to make a call to Amplify.API.post I get the following error:
[Amplify] AWSMobileClient Event listener - signedOutFederatedTokensInvalid
Failed APIError: Failed to retrieve authorization token.
Caused by:
AuthError: Session expired could not fetch cognito tokens
Recovery suggestion: Invoke Auth.signIn to re-authenticate the user
My function for doing the POST is as follows :
func postTest ()
{
let message = #"{'message": "my Test"}"#
let request = RESTRequest (path: "/test", body: message.data(using: .utf8))
Amplify.API.post (request:request)
{
result in switch result
{
case .success(let data):
let str = String (decoding: data, as: UTF8.self)
print ("Success \(str)")
case .failure(let apiError):
print ("Failed", apiError)
}
}
}`
I then went into the API Gateway UI and changed the generated Method Request on my resource from AWS IAM to my Cognito User Pool Authorizer thinking this was the issue. I also changed the awsAPIPlugin authorizationType to "AMAZON_COGNITO_USER_POOLS" in my amplifyconfiguration.json file. This unfortunately did not have any affect.
I've seen posts such as this issue User is not created in Cognito User pool for users logging in with Google federated login #1937 where people discuss the problem of having to to use a web ui to bring up the social sign in. I understand that Apple will reject your app sometimes for this. Therefore this is not a solution.
I then found this post which seems to resolve the issue however this appears to use the old version of the SDK? Get JWT Token using federatedSignIn #1276
I'm not great with Swift (I'm still an Objective C expert, but am slowly learning Swift) so I'm uncertain which path to go here and whether this is actually a solution? It does seem to be quite more complicated than the function I have that does my POST? The RESTRequest does seem to be a simple and easy solution but I'm uncertain how to pass it the Authorization token (or even how to get the token if it is needed here).
However, everything I've read about the SDK is that the authorization should be handled automatically in the background according the docs in my first link above. Specifically pointed out, again, here : Cognito User pool authorization. The last paragraph here states 👍
With this configuration, your access token will automatically be included in outbound requests to your API, as an Authorization header.
Therefore, what am I missing here as this does not appear to automatically include my access token to my outbound requests to my API?

iOS Firebase OTP verification without Sign Up

I need help verifying the OTP with Firebase.
I Managed to receive a SMS with the OTP but when I verify it I get automatically signed up and I only know if the OTP was valid if I signed up - else I get a popup like "invalid otp".
How can I manually validate the otp? My goal is to open another screen where the user puts in more information.
func verifyCode(){
let credential = PhoneAuthProvider.provider().credential(withVerificationID: self.CODE, verificationCode: code)
print(credential)
loading = true
//here i just want to verify my OTP without signing in...
Auth.auth().signIn(with: credential) { (result, err) in //here i am signing in...
self.loading = false
if let error = err{
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.error)
self.code = ""
self.errorMsg = error.localizedDescription
withAnimation{ self.error.toggle()}
return
}
self.gotoRegistration = true
withAnimation{self.status = true}
}
}
There is no way to use Firebase Authentication's phone/OTP provider without automatically signing the user in.
But the fact that the user is signed in to Firebase, does not mean that you have to grant them access to all parts/data in your app. If you want them to provide more information, you can do so before or after signing them in to Firebase, and make it part of the same sign-up flow as far as the user is concerned.
So something like:
// Sign the user in with Firebase
// Check if the user has provider the additional registration information
// If not, send them to the registration information screen
// If so, send them to the next screen of the app
You can also enforce these rules in your back-end code, or (if you use one of Firebase's back-end services) in the server-side security rules.

Swift - Firebase Authentication State Persistence

I'm currently thinking about implementing Firebase Auth to my Swift project, hence I've been reading some articles. - Namely among others this one.
I need some help understanding the given article. It's about "Authentication State Persistence". Does this mean, that if the value is set to local, the user will stay logged in even after closing the app? In other words, will he be able to sign up once and stay logged in until he decides to log out - even when he's offline?
Let's say a user decides not to create an account and logs in with "Anonymous Authentication" (I assume this is the type of login in this kind of case) - will he stay logged in forever as well or is there a danger of data loss, in case of going offline or closing the app?
First: the link you provided refers to a javascript firebase documentation
Second: the only thing available in IOS is you can create an anonymous user with
Auth.auth().signInAnonymously() { (authResult, error) in
// ...
let user = authResult.user
let isAnonymous = user.isAnonymous // true
let uid = user.uid
}
and you can convert it to a permanent user check This
Finally: whether the user is usual / anonymous , after you sign in you need to check this to show login/home screen every app open
if FIRAuth.auth()?.currentUser != nil {
print("user exists")
}
else {
print("No user")
}
and the user still exists unless you sign out regardless of whether you closed the app or not
If you are using the latest Firebase version, FIRAuth is now Auth:
if Auth.auth()?.currentUser != nil {
print("user exists")
}
else {
print("No user")
}

Auth0 "Lock" for Swift Username-Password Login not working

I have set up a Swift App with the Auth0 Web Login and everything works fine. Then i have tried to implement the "Lock" login with the result that social media login works perfectly well, but i cannot login via the username-password method.
On my Auth0 database, the signed-up user shows up (indicating that sign up of new username-passoword user actually work) and testing the login itself on the Auth0 Homepage works fine as well. Just when trying to login with the Lock widget, i get an error: "We're sorry, something went wrong when attempting to log in.". I also tried verifying the registered E-Mail, but that did not solve the issue either.
Any ideas, what might go wrong here?
After also pointing that issue out to Auth0/Lock support, a solution was found. Maybe this helps people, having the same problem: When using the Lock client inside some VC:
Lock
.classic()
.withOptions {
$0.scope = "openid profile"
$0.oidcConformant = true
$0.logHttpRequest = true
}
.withStyle {
$0.title = "App Name"
}
.onAuth { credentials in
print("successful login")
}
.onError { error in
print("Failed with error \(error)")
}
.present(from: self)
instead of the web login:
Auth0
.webAuth()
.audience("https://alienbash.eu.auth0.com/userinfo")
.start {
switch $0 {
case .failure(let error):
// Handle the error
print("Error: \(error)")
case .success(let credentials):
// Do something with credentials e.g.: save them.
// Auth0 will automatically dismiss the hosted login page
print("Credentials: \(credentials)")
}
}
one has to make sure to change "Grant_Type" the Auth0 client settings to also allow the "Password" Grant. In order to do that, in your Auth0 client go to:
Settings --> Advances Settings --> Grant Types
and make sure to check "Password as this checkmark is unchecked by default when creating a new Auth0 client and will be inevitable when using the "Lock" client.

AWS Cognito check and get users

I'm building an iOS App that is using Amazon MobileHub. Currently it's associated with Cognito and the sign up and sign in flow works great.
What I'm trying to achieve is for one user to be able to add another user as a friend so to speak. To make that possible, I need to check if a user with a specific username exists and if it does, get some attributes such as the name of that target user.
I've tried to use the get user > get details function but it gives me an error Authentication delegate not set.
Here's the code I used:
var pool: AWSCognitoIdentityUserPool?
let user = pool?.getUser(usernameField.text!)
self.pool = AWSCognitoIdentityUserPool.init(forKey: AWSCognitoUserPoolsSignInProviderKey)
user?.getDetails().continueWith { (task: AWSTask<AWSCognitoIdentityUserGetDetailsResponse>) -> Any? in
if let error = task.error as NSError? {
print("ERROR: " + error.localizedDescription)
return ""
}
print(task.result)
return ""
}
An approach I thought of was to store the username and the attributes I want to access to DynamoDB and then access it there but that will just create double unnecessary entries.
The issue you'll run into is that user attributes aren't publicly visible. Only the user who has signed in can call GetUser. If it's a back end process, you could do this via the AdminGetUser operation, but this looks client side so I wouldn't recommend that. The only real way around this would be to do what you suggested at the bottom of your post, ultimately.

Resources