realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.8k stars 576 forks source link

JWT metadata missing on User object #3268

Closed rvanmil closed 3 years ago

rvanmil commented 4 years ago

Goals

I have specified metadata fields in the custom JWT authentication settings, but these fields do not appear on the user object after logging in. I am working with realm-web version 0.9.0

Expected Results

When using the Stitch SDK these fields could be found on the user.profile.data object (mongodb-stitch-browser-sdk version 4.8.0).

Actual Results

The user.profile.data object does not exist. See screenshots.

Steps to Reproduce

Use custom JWT authentication with metadata fields. Login in the browser and check the logged in user object.

Code Sample

const loggedInUser = await realmApp.logIn(Realm.Credentials.jwt(jwtString))
console.log(loggedInUser.profile.data) // undefined

Version of Realm and Tooling

rvanmil commented 4 years ago

The HTTP request to https://eu-west-1.aws.stitch.mongodb.com/api/client/v2.0/auth/profile does return the missing data fields, so I think this is a problem in the code which parses that response.

nirinchev commented 4 years ago

Shouldn't that go into user.customData?

rvanmil commented 4 years ago

I don’t think so, that is a different feature.

kraenhansen commented 4 years ago

I can see on the screenshot that you're using a slash in the key path when setting up metadata fields. Are you sure those shouldn't be dots? See dot notation.

That being said, there might very well be an issue here we need to investigate. Can you confirm the data is not present on the customData property? Are you using other SDKs where you're observing a different behavior?

rvanmil commented 4 years ago

I've done some investigating by comparing the realm-web source to the mongodb-stitch-browser-sdk source and I have found the cause of this issue.

Both SDK's fetch the user profile and both receive the same response from the server, including the data object that is currently missing from the Realm user (and which was not missing from the Stitch user). There is a difference in the way the SDK's parse the response from the server though.

The Stitch SDK uses the following field mapping to copy the data into the profile:

enum Fields {
  DATA = "data",
  USER_TYPE = "type",
  IDENTITIES = "identities"
}

See here: https://github.com/mongodb/stitch-js-sdk/blob/e7308409377bf98b65f291be3d6860722f23f5c3/packages/core/sdk/src/auth/internal/CoreStitchAuth.ts#L978 https://github.com/mongodb/stitch-js-sdk/blob/e7308409377bf98b65f291be3d6860722f23f5c3/packages/core/sdk/src/auth/internal/models/ApiCoreUserProfile.ts#L39

The Realm Web SDK uses a different mapping. This mapping does not contain the data property, which explains why it is missing from the user profile object.

const DATA_MAPPING: { [k in DataKey]: keyof UserProfile } = {
    [DataKey.NAME]: "name",
    [DataKey.EMAIL]: "email",
    [DataKey.PICTURE]: "pictureUrl",
    [DataKey.FIRST_NAME]: "firstName",
    [DataKey.LAST_NAME]: "lastName",
    [DataKey.GENDER]: "gender",
    [DataKey.BIRTHDAY]: "birthday",
    [DataKey.MIN_AGE]: "minAge",
    [DataKey.MAX_AGE]: "maxAge",
};

See here: https://github.com/realm/realm-js/blob/99e5df137068704790bd03770e630741928ab686/packages/realm-web/src/User.ts#L245 https://github.com/realm/realm-js/blob/99e5df137068704790bd03770e630741928ab686/packages/realm-web/src/UserProfile.ts#L127

kraenhansen commented 4 years ago

Thanks a lot for the initial investigation, I agree we have a discrepancy here which we need to get fixed.

rvanmil commented 4 years ago

Would it help and/or speed things up if I submit a PR which fixes this? I’m guessing I should use the v10 branch as starting point?

kraenhansen commented 4 years ago

That would be awesome. I think we need to do a bit of refactoring in the way the GET /profile is parsed, but if you want to give it a go, it would be highly appreciated.

andrew-whitmore commented 3 years ago

@kraenhansen - should this work now?

I have version 10.2.0 of realm using a custom JWT authentication provider and custom profile data is not working as expected. As a work around we are currently using the birthday field on profile to pass a value down that we need. See screen shot Screenshot 2021-02-08 at 16 24 36

then after login If I inspect the profile like so

console.log(user.profile);

then the opu field is not present.

{"birthday": "7523", "firstName": "ALEX M", "lastName": "DUMMER", "name": "770540"}

Thanks

Andy

kraenhansen commented 3 years ago

@andrew-whitmore short answer is no.

3481 fixed this for Realm Web (since that was the SDK the original poster was using), but we still have outstanding issues adding this across our other SDKs. I'll ensure these issues are tracked and get back here with a link so you can follow the progress.

rvanmil commented 3 years ago

@kraenhansen posting this here because it has a recent reply. I you prefer me to create a new issue let me know.

I have upgraded one of our web apps from the old stitch SDK to the new realm web SDK. Everything works properly and I am receiving the Auth0 data now. Thanks again for fixing this 🙏

There's only one small issue with TypeScript. All the additional properties on user.profile are declared as string: https://github.com/realm/realm-js/blob/3632b78cd84117c52eca9058700c889b4f0049f5/types/app.d.ts#L614

This is a problem, because these properties can also be any other type, for example the app_metadata and roles as seen on this screenshot:

realm-custom-data

Which means I have to convert the property to unknown (to get rid of the string type) before I can use them, for example:

const roles = (user.profile.roles as unknown) as Record<string, boolean>
const app_metadata = (user.profile.app_metadata as unknown) as MyAppMetadata

Would it be possible to change the type of the additional properties to [key: string]: unknown ?

kraenhansen commented 3 years ago

@rvanmil I'm happy that it's working and I agree unknown is better here. I've created a PR with the change: #3576

I want to make sure I also mention that we've made the User class parametric on the profile. I do see however that we're not (yet) adding this as a type parameter of App as we did with functions and custom data though. This should enable declaring the exact type for the user profile. I can share an example once I'm on my computer if it's not too obvious how someone would do that.

rvanmil commented 3 years ago

Thanks!

This should enable declaring the exact type for the user profile.

That would be even better than having unknown types 😊 If you could share an example that would be great.