I'm working on an app that currently uses email/password auth provided by MongoDB Realm. I'm thinking of switching to using the custom JWT auth for various reasons. I'm quite extensively using the custom user data to store all sorts of things. When I switch from email/password to custom JWT the login works, but the custom user data is empty...
This works fine:
const jwt = await axios.post("https://MYAPI.COM/login", {
user: email.value,
password: password.value,
});
console.log(`jwt: ${JSON.stringify(jwt.data)}`);
const credentials = Realm.Credentials.emailPassword(
email.value,
password.value
);
// const credentials = Realm.Credentials.jwt(jwt.data);
console.log("logging in");
const user = await realm.logIn(credentials);
await user.refreshCustomData();
const customUserData = await user.refreshCustomData()
console.log(`Logged in as ${JSON.stringify(user)}`);
console.log(`customUserData: ${JSON.stringify(customUserData)}`);
When I uncomment the line changing the credentials the custom user data is empty
I was running into a similar problem using Custom Function for authentication.
I was mapping the userId incorrectly -
custom user data is based on the ID of the authenticated user, please make sure that the user ID is mapped correctly in the corresponding collection.
https://www.mongodb.com/docs/realm/users/enable-custom-user-data/
Related
I'm migrating my ServiceStack Ormite MVC application to use the JWTAuthProvider for stateless auth. I have this working by authenticating as normal, and setting the returned BearerToken and RefreshToken on a successful auth:
using (var authService = HostContext.ResolveService<AuthenticateService>(ServiceStackRequest))
{
var response = await authService.PostAsync(new Authenticate
{
provider = CredentialsAuthProvider.Name,
UserName = model.UserName,
Password = model.Password,
RememberMe = true,
});
var authResponse = response.GetDto() as AuthenticateResponse;
Response.Cookies.Append("ss-tok", authResponse.BearerToken, new CookieOptions() {...});
Response.Cookies.Append("ss-reftok", authResponse.RefreshToken, new CookieOptions() {...});
}
This appears to work for some users and not for others. The problem seems to be that user accounts with a lot of permissions end up with much larger BearerToken values, some over 4096, so these cannot be set for the ss-tok cookie.
The JWT Auth provider docs provide references to the CreatePayloadFilter and the PopulateSessionFilter, however these are only used when creating a session from a token, not the other way around. I want to filter out items (the permissions in particular) when serializing to a token.
Ideally the permissions would be excluded if there are too many (or always be excluded if that's not possible) and would be lazy-loaded when accessed. This may be possible with a custom AuthUserSession inheriting from the base AuthUserSession that Lazy-loads the Permissions, but I don't know how I could do this without the JWT Provider loading the permissions to serialise too.
I have implemented a custom UserStorageProvider with AbstractUserAdapter for Keycloak for retrieving users from external DB and login users with credentials stored in that DB. All works ok and the data is read only via Keycloak admin panel.
I wanted to add additional attributes to users from data stored in external DB, I would like to add this data to the token via Attribute Mapper, is there a way to do it? Or do II need to implement AbstractUserAdapterFederatedStorage? The problem with the later is that it is not read only and allows to edit the user data transferred to the keycloak user store.
It really depends on your implementation. If you have access to desired data for attributes and to the user, you can simply assign new attributes to him, i.e:
KeycloakSession session = // get session somewhere
RealmModel currentRealm = session.getContext().getRealm();
UserModel user = getUserSomehow(session, currentRealm);
user.setSingleAttribute("attributeName", "attributeValue");
...
private UserModel getUserSomehow(KeycloakSession session, RealmModel realm) {
return KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), "<username>");
// or (cached model):
// return session.users().getUserById("<userId>", realm);
// or (Un-cached model):
// return session.userStorageManager().getUserById("<userId>", realm);
}
I'm trying to reset/change the token (JWT) for users who changed their passwords on NestJS API with PassportJS. Here is a clean example of how this authorization works: https://docs.nestjs.com/security/authentication.
I want to generate a new token on password change to make sure, that on every device on which the user was logged in, after password change they will get unauthorized and so logged out.
This is how I handle the password change in users service:
async changePassword(uId: string, password: any) {
return await this.userRepository.createQueryBuilder()
.update(User)
.set({ password: await bcrypt.hash(password.value, 10) })
.where("userId = :userId", { userId: uId })
.execute();
}
There are no prebuild methods to do this I think. JwtService got only 5 methods: decode, sign (this one is used to generate a token), signAsync, verify and verifyAsync.
So how can I do this properly?
You'd need some sort of way to invalidate the JWT that was already given to the user. As you can't just do that to a token, generally (it's stateless, it holds its own validity) you'd need to create a JWT restrictlist in a database that you check the incoming JWT against. If the JWT is in the restrictlist, reject the request. Otherwise, let it through (if it's valid of course)
I have 2 possible realms to authenticate my users in my webapplication.
here are a few lines from my shiro.ini:
securityManager.realms = $ldapRealm, $saltedJdbcRealm
strategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $strategy
Authentication works fine for both realms and the FirstSuccessfulStrategy works fine as well.
In my custom AuthenticationFilter within the executeLogin() method I have this code to do the login:
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
currentUser.login(token);
How can I now determine which realm was resposible for the authentication after the .login() method is executed?
If the user was authenticated via the LDAP Realm I would like to get some more information about the user from the LDAP.
Does anyone know how this can be done?
Subject subj = SecurityUtils.getSubject()
SimplePrincipalCollection spc = (SimplePrincipalCollection) subj.getPrincipals();
Set<String> realmNames = spc.getRealmNames();
The realmNames variable should contain one element, the realm that authenticated the user.
If your realm implementation is a standard one then the SimpleAuthenticationInfo created when the user is authenticated will have been created with the name of the realm that successfully authenticated the user.
Passport.js provides authentication framework in Node.js. It only deals with Authentication.
Now I would like to enable password reset. Since there is no password field in User model, only passports, how can I reset password in passport-local strategy? I assume that user needs to generate a new password and call something to override the existing hash of the old password. What methods are those and where can I find them?
When the user selects to reset his/her password, what you can do is send an email to the user with a link containing a token associated with the user. Once the user clicks on the link, you validate the user based on the token & email and then show the reset password HTML. Once user enters the new password, in the backend code, you set the password on the User object after hashing and then save it. You can set the token as null too.
A sample code with base64 will be as shown below
user.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
user.password = user.hashPassword('newPassword');
user.token = undefined;
user.save(...)
The hashPassword method is as given.
UserSchema.methods.hashPassword = function(password) {
if (this.salt && password) {
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
} else {
return password;
}
};
The above code is auto-generated with Yeoman