Atlas and Realm Users Question

Hello, everyone.

I am extremely new to MongoDB, Realm and Atlas. I have been fighting with getting my IOS app to connect to Realm for about two months and I am completely confused. Every time I think I am about to figure it out I get stuck again. I am sincerely hoping someone can help me better understand the Relationship between Realm and Atlas users.

My issue is that I am getting a permission denied error: Code 206:

2021-09-07 07:15:40.895880-0500 Traction on Realm[6804:414559] Sync: Connection[1]: Session[1]: Received: ERROR “Permission denied (BIND, REFRESH) - request logs URL: MongoDB Realm” (error_code=206, try_again=true)

Here are the sync configuration that I have for both read and write:

{
  "%%user": "%%partition"
}

So my fundamental questions are:

  • What’s the relationship between an Atlas User and a Realm User?
  • How do I make sure the Realm user knows that the Atlas user (which can’t be defined by an e-mail address) is the same?
  • Where do I need to look to start trying to figure out what’s going on?

Please let me know what additional code or settings might be useful.

1 Like

Hi @Amy_Young ,

Answering your questions:

What’s the relationship between an Atlas User and a Realm User?

None: Atlas users, in the context of a Realm App, are typically the users that have privileged access to the cluster and/or the databases, as maintainers, admins, etc. On the other hand, each Realm App (and you can have multiple in the same cluster) has its own set of users, that register and sign in via the providers you specify, and are not Atlas users.

How do I make sure the Realm user knows that the Atlas user

They don’t, they live in separate contexts, and typically there’s no reason why they would need to communicate: what would be your use case for them to be aware of each other?

Where do I need to look to start trying to figure out what’s going on?

In the setup that you report: “%%user”: “%%partition”, the partition value the user has permissions to access is supposed to be 60c28192a53c1ae905427d96, but you have a value of _partition=60c28192a53c1ae905427d96 instead, hence the permission fails. You should remove the _partition= bit then.

4 Likes

So in other words I believe that the atlas user would be the developer, and the realm user would be whatever user that developer gave the credentials 2 (the client) in order for them to now become the realm user if I’m not mistaken. It is a possibility that I am mistaken. Thus is my current level of understanding on this.

@Jason_Nutt

I believe that the atlas user would be the developer

Correct, even though a better definition will be whoever needs access to Administration and Maintenance tasks on the cluster (that in larger companies may not necessarily be just the Developers)

whatever user that developer gave the credentials 2 (the client)

In general, a Realm user is simply an app’s user, identified or anonymous: for example, with Email/Password Provider a user can sign up once, then log in for later connections, all without any intervention from the developer. If there are more complex scenarios (like, paying users that have different levels of features), there must be some logic somewhere to grant the proper access.

3 Likes

That clarified so much for me @Paolo_Manna . Thank you for that. :sunny:

3 Likes

Thanks for the detailed answer. I’m sorry its been a while. Life happened. But, now I am determined to get back to this.

I understand that removing the %%user: %%partition setup would solve my problem. But, doesn’t that eliminate the capability of limiting users to their own partitions? Since there is only one user right now, where did the other partition come from? How do I get rid of it and get the right partitions going?

Aren’t the partition values you mentioned the same: 60c28192a53c1ae905427d96 and 60c28192a53c1ae905427d96? Why isn’t that working then?

Hi @Amy_Young ,

I understand that removing the %%user: %%partition setup would solve my problem.

No, you misunderstood my answer: %%user: %%partition is perfectly valid, it’s the way that you set the partition value that’s a mismatch.

With that setting, you’re saying: “I only give permission to a user to access a partition that matches the user itself”, thus, if the user has _id set to 60c28192a53c1ae905427d96, the partition value must match that exact string (or ObjectId, depending on your schema).

However, you’re setting the partition value at _partition=60c28192a53c1ae905427d96, i.e. you’re adding a _partition= prefix that doesn’t belong there. In other words, to set a partition value you only need to set the value itself, no prefixes, suffixes or anything additional. There may be cases where these may be useful (when you’ve partition values based on complex keys, for example), but not in your simple case.

Hope it’s clearer now!

So where am I adding the _partition prefix that doesn’t belong there? I thought I understood that that’s what we needed to do to set the partitions.

In your reply, you say:
With that setting, you’re saying: “I only give permission to a user to access a partition that matches the user itself”, thus, if the user has _id set to 60c28192a53c1ae905427d96 , the partition value must match that exact string (or ObjectId , depending on your schema).

Isn’t that what I want to do if I want the user to only be able to access their details?

Can you please share the code snippet where you’re setting the partition value? It could typically be during the creation of the object itself, or right after, before inserting it into the DB.

I haven’t even gotten that far. I am just trying to get my app to let me login and get to the next screen.

Here’s the class object though:

class Dog: Object, Identifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var name: String = “”
@Persisted var breed: String = “”
@Persisted var birthday: Date = Date()
@Persisted var _partition: String = “”
@Persisted var gender: String = “”
// var age: Int {
// return getAge(birthday: birthday)
// }

convenience init(name: String) {
    self.init()
    self.name = name
}

}

At some point, after login, you should have something like:

user.configuration(partitionValue: partitionValue)

What do you set there as partitionValue?

Here’s what I have for the partition configuration:
let configuration = user.configuration(partitionValue: “_partition=(user.id)”)

Here’s the whole code:

     @IBAction func loginPressed(_ sender: UIButton) {
        if let email = emailText.text
        , let password = passwordText.text {
            print("Log in as user: \(email)")
            app.login(credentials: Credentials.emailPassword(email: email, password: password)) { [weak self](result) in
                DispatchQueue.main.async {
                    switch result {
                    case .failure(let error):
                        // Auth error: user already exists? Try logging in as that user.
                        print("Login failed: \(error)")
                        self!.userMessageText.text = "Login failed: \(error.localizedDescription)"
                        return
                    case .success(let user):
                        print(user.id)
                        print("Login succeeded!")
            
                        // Load again while we open the realm.
                        // Get a configuration to open the synced realm.
                        let configuration = user.configuration(partitionValue: "_partition=\(user.id)")
                        // Open the realm asynchronously so that it downloads the remote copy before
                        // opening the local copy.
                        Realm.asyncOpen(configuration: configuration) { (result) in
                            DispatchQueue.main.async {
                                print ("attempting dispatch")
                                switch result {
                                case .failure(let error):
                                    print(error)
                                    fatalError("Failed to open realm: \(error)")
                                case .success:
                                    self!.ShowHome()
                                }
                            }
                        }
                    }
                }
            }
        
        }
    }

Precisely, that’s where you’re adding the unnecessary prefix, the partitionValue should be just the user.id, i.e.

let configuration = user.configuration(partitionValue: user.id)
1 Like

That helped tremendously, Paolo.

However, I’m still not getting to the end. Now it is at least getting to the line of code that says "print (“attempting dispatch”).

Here’s the error I am receiving now:

2021-10-19 06:32:54.428943-0500 Traction on Realm[29288:2524611] Sync: Connection[1]: Disconnected

Error Domain=io.realm.unknown Code=89 “Operation canceled” UserInfo={Category=realm.basic_system, NSLocalizedDescription=Operation canceled, Error Code=89}

Traction_on_Realm/WelcomeVC.swift:55: Fatal error: Failed to open realm: Error Domain=io.realm.unknown Code=89 “Operation canceled” UserInfo={Category=realm.basic_system, NSLocalizedDescription=Operation canceled, Error Code=89}

2021-10-19 06:32:54.429326-0500 Traction on Realm[29288:2524339] Traction_on_Realm/WelcomeVC.swift:55: Fatal error: Failed to open realm: Error Domain=io.realm.unknown Code=89 “Operation canceled” UserInfo={Category=realm.basic_system, NSLocalizedDescription=Operation canceled, Error Code=89}

It feels like it is saying it doesn’t know my Realm or that maybe my App ID is wrong? Any ideas?