Realm Object Server - Error: Your request parameters did not validate - swift

I built a small iOS application which uses Realm instead of CoreData. The app does not require a login as it only stores data entered by the user. I'm currently trying to save users data so that if a user deleted the app for example, the data will be there by default the next the app is re-installed.
Here's where I am getting confused. Can I still use Realm Mobile Platform even though the app will not require a login screen. (i.e. data will automatically be saved for users who are logged-in to their iCloud accounts).
Here's what I've done so far:
I configured Realm Object Server on an AWS EC2 instance, and I can login to the realm dashboard through the browser just fine.
I configured the cloudKit stanza in the configuration.yml file as per the authentication instructions.
In my setupRealm() func, I tried the following code but I keep getting a parameters validation error:
SyncUser.logIn(with: cloudKitCredentials,
server: serverURL) { user, error in
if let user = user {
print("in")
}
else if let error = error {
fatalError(String(describing: error))
// Error: "Your request parameters did not validate."
}
This is the error message:
Error Domain=io.realm.sync Code=3
"Your request parameters did not validate."
UserInfo={statusCode=400,
NSLocalizedDescription=Your request parameters did not validate.}:
I suspect that the my iCloud user is not being tied with the object server, but I can't seem to put the pieces together. I'd appreciate any pointers.

The server requires a restart after editing the authentication lines in the configuration.yml.

Related

Duplicated anonymous users when session expired in Parse platforms

if let cachedUser = PFUser.current() {
// proceed to save some objects
} else {
PFAnonymousUtils.logIn{ (user, error) in
// proceed to save some objects
if ((error as NSError).code == 209) {
// session expired, logout and call PFAnonymousUtils.logIn again later
PFUser.logOut()
}
}
}
For a simple Swift mobile app, we save data on parse backend anonymously. If there is session expiration error (1 year default on Parser server), we will have to do something about it or we wont be able to save anything anymore. We therefore logout and re-login again.
Once we logout and re-login again, this creates a second new User on the backend.
This creates a problem - we no longer have an accurate picture of the number of users on the backend.
What was wrong in the flow above? Is there a way to prevent duplicated anonymous user when handling expired session?
It is possible to increase the default session duration in your server configuration.
You can also add the code below to your server configuration...
expireInactiveSessions: false
This thread may provide further useful insights into this issue.

SMAPI Alexa Read Scope in Swift

I'm trying to get read & write permissions, so users can see their alexa skill from an ios app.
I successfully managed to let the user sign in with their amazon account (via the LWA iOS SDK). When I add the profile scope to the authentication process I get this error when trying to make a get request to the skill endpoint:
"User has not consented to this operation."
So I added the alexa::ask scope, so I get the right permissions:
let scopeData_alexa: [AnyHashable:Any] = ["productID" : AmazonManager.shared.productId, "productInstanceAttributes": [ "deviceSerialNumber": uniqueDeviceSerialNumber]]
let readPermissions = AMZNScopeFactory.scope(withName: "alexa::ask:skills:readwrite", data: scopeData_alexa)
When I try to authenticate the user I get this response:
Error Domain=AMZNLWAErrorDomain Code=2 "(null)" UserInfo={AMZNLWAErrorNonLocalizedDescription=The+scope+data+list+you+provided+is+invalid+for+your+request}
As said above, the normal login works fine. The scope Data is also working, when I ask the user for Alexa Voice Services.
What to I have to change? Any solutions?
It was super easy to fix.
just remove the data parameter
let readPermissions = AMZNScopeFactory.scope(withName: "alexa::ask:skills:readwrite")
Then it should work fine!

Checking if a user already signed up

I built a custom authentication system using FirebaseAuthentication tokens.
My signup / login flow should work like this:
User presses login button
My server generates the authentication token and sends it to the client
Check if the user already exists (in the 'Auth' table or in my database?)
If true: sign in using FIRAuth.auth()?.signIn(withCustomToken:...
If false: Show a form to to enter custom information (name, etc..)
sign using FIRAuth.auth()?.signIn(withCustomToken:...
save the custom information to my database
My question is: How can I find out if the user has already signed up?
Would a publicly accessible database with only uid's be the way to go?
This is fairly opinion based, but yes, I would use a standalone DB that stores each user's username who has signed up. Then all that is required is a quick web request through a PHP file querying for any rows returned with that username.
The firebase sign in method will feedback in asynchronous callback.
FIRAuth.auth()?.signInWithEmail(email, password: password, completion: { (user , error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(user)
})
If you haven't sign up yet. The error will print out
There is no user record corresponding to this identifier. The user may have been deleted.

Google Sign-In with Passportjs not getting authenticated

I'm using Sails with Passport for authentication. I'm using passport-google-oauth(OAuth2Strategy) and passport-facebook for enabling Google Sign-in.
I'm not too well-versed with Passport, so pardon me if this is a rookie question. I've set up login via Facebook and it works just fine. With Google, I do receive an authorization code after allowing access to the app, but the I'm eventually not authenticated. I'm guessing the same code should work for both Facebook and Google since the strategies are both based on oauth2.
I'm not even sure what code to share, since I'm using the auto-generated code from sails-generate-auth, but do let me know if there's anything else I can share.
Any ideas on why this might be happening? The app is locally hosted but that's unlikely to be the problem since I am getting to the authorization stage anyway.
I faced the same problem and it was located here in in api/services/passport.js:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
The Google service was not returning a profile.username property.
Because of it, the user is not saved in the database and cannot be authenticated. Then the passport callback receives an empty user, so the function that handles errors is fired and the user is redirected to the login page.
This change allows to use the displayName property as the username:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
/** Content not generated BEGIN */
// If the username property was empty and the profile object
// contains a property "displayName", add it to the user.
if (!user.username && profile.hasOwnProperty('displayName')) {
console.log(profile); // <= Use it to check the content given by Google about the user
user.username = profile.displayName;
}
/** Content not generated END */
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
You could also use the profile.id property because profile.displayName is not necessarily unique (ie: two Google accounts can have an identical displayName). But it is also true accross different services: a Twitter account could also have the same username than a Facebook account. If both register on your application, you will have a bug. This is a problem from the code generated by sails-generate-auth and you should adapt it with the behavior that you want.
I will propose a PR if this solution works for you too.
Alright, so this ultimately turned out to be a known issue with the API.
TL;DR: Enable the Google+ API and the Contacts API as mentioned here. (The Contacts API isn't required, as #AlexisN-o pointed out in the comments. My setup worked as desired with Contacts API disabled. This obviously depends on what scope you're using.)
I believe it's not a nice way of failing since this was an API error that was prevented from bubbling up. Anyway, I dug into passport.authenticate to figure out what was going wrong. This eventually calls the authenticate method defined in the package corresponding to the strategy (oauth2 in this case). In here (passport-google-oauth/lib/passport-google-oauth/oauth2.js) I found that the accessToken was indeed being fetched from Google, so things should be working. This indicated that there was a problem with the requests being made to the token urls. So I ventured a little further into passport-oauth2/lib/strategy.js and finally managed to log this error:
{ [InternalOAuthError: failed to fetch user profile]
name: 'InternalOAuthError',
message: 'failed to fetch user profile',
oauthError:
{ statusCode: 403,
data: '{
"error": {
"errors": [{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}],
"code": 403,
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration."
}
}'
} }
This was the end of the hunt for me and the first result for the error search led to the correct answer. Weird fix though.

Facebook login WinJS Store app issues

I tried following this blog post
Which explains how to setup up facebook login on a WinJS app.
I got it all working, got the app ids set and the authentication dialog is showing the correct app name and authentication stuff, however when the app redirects the app receives this error (after closing the dialog: "The specified protocol is unknown") and the dialog shows the error message: "We can't connect to the service you need right now. Check your network connection or try this again later".
the error stack:
"WinRTError: The specified protocol is unknown.\r\n\n at getResultsOfAsyncOp (Function code:338:5)\n at op.completed (Function code:427:21)
Actual calling code:
var loginURL = "https://www.facebook.com/dialog/oauth?client_id=[snip]&display=popup&scope=user_about_me&response_type=token&redirect_uri=ms-app://s-[snip]/"
Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
Windows.Security.Authentication.Web.WebAuthenticationOptions.none,
new Windows.Foundation.Uri(loginURL))
.then(function success(result) {
}, function error(error) {
});
Hopefully anyone here has any idea why this error message is thrown.
We managed to solve the issue.
The sid from the store was different from the sid of the app during local debugging. By changing the appmanifest -> packaging -> publisher certificate to a local certificate with the CN provided in the store settings the sid is updated to be equal to the one in the store.
et voila, it works.