Firebase authentication with localId / idToken (instead of email / password) - reactjs

In my app, when a user logs in, I use firebase.auth to authenticate the user based on the email/password the user typed:
firebase.auth().signInWithEmailAndPassword(userInputs.email.value, userInputs.password.value)
Then I dispatch it to the redux state and also set the received localId and idToken on the local storage:
localStorage.setItem('token', response.user.qa);
localStorage.setItem('localId', response.user.uid);
When the user closes the app window and then reopen the app later, the localId and idToken are still set in the localstorage, but to re-authenticate I need to supply email and password. Is it possible to authenticate with localId/idToken, or should I save the email/password on localStorage instead of saving the two tokens?
Upon checking if the user is authenticated:
var user = firebase.auth().currentUser;
console.log(user);
I get 'null'.
It seems that I must sign in even if I already have the localId, without signing in I don't have access to the database.
Also, obviously my database rules grant access to the db only to authenticated users:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Thanks in advance!

You don't have to store the email & password in the localstorage.
Firebase library automatically retain the auth infomation locally.
The cause of you get null is you are trying to get user info with Synchronous code.
Which means that you are trying to get user before the firebase library's initalization.
firebase.auth().currentUser; // <= synchronous
Following code runs Asynchronously and you can get user after the firebase library initalize.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});

Related

MS Teams permissions for creating a group

Can someone help me understand how to add a permission to a MS-Graph API call?
I'm trying to create a new team/group but I'm getting a permission error. Obviously I need add the Team.Create permission if I want to create a Team. Which I did as seen in the image below
Here's the sample code where I tried to add the permission to the MSAL client request:
// Initialize Graph client
const client = graph.Client.init({
// Implement an auth provider that gets a token
// from the app's MSAL instance
authProvider: async (done) => {
try {
// Get the user's account
const account = await msalClient
.getTokenCache()
.getAccountByHomeId(userId);
let scope = process.env.OAUTH_SCOPES.split(',');
scope.push("Team.Create");
console.log("Added a extra permission request");
console.log("scope = " + scope);
if (account) {
// Attempt to get the token silently
// This method uses the token cache and
// refreshes expired tokens as needed
const response = await msalClient.acquireTokenSilent({
scopes: scope,
redirectUri: process.env.OAUTH_REDIRECT_URI,
account: account
});
console.log("\nResponse scope = " + JSON.stringify(response) + "\n");
// First param to callback is the error,
// Set to null in success case
done(null, response.accessToken);
}
} catch (err) {
console.log(JSON.stringify(err, Object.getOwnPropertyNames(err)));
done(err, null);
}
}
});
return client;
Then I get the following error:
The user or administrator has not consented to use the application with ID 'xxxxxxx'
named 'Node.js Graph Tutorial'. Send an interactive authorization request for this user and resource
I did give permissions to Team.Create in the Azure Active Directory, so how do I consent to this app gaining access? Note this code is the tutorial for learning Graph: https://learn.microsoft.com/en-us/graph/tutorials/node
Judging by the screenshot, you can't give admin consent to the permission as it is grayed out.
You'll need to try if you can grant user consent.
acquireTokenSilent won't work in this case since consent is needed.
You need to use one of the interactive authentication methods to trigger user authentication, at which time you can consent to the permission on your user's behalf.
In that sample specifically, you probably need to modify the scopes here: https://github.com/microsoftgraph/msgraph-training-nodeexpressapp/blob/08cc363e577b41dde4f6a72ad465439af20f4c3a/demo/graph-tutorial/routes/auth.js#L11.
And then trigger the /signin route in your browser.

Why is Identity Server4 Logout not working? (without MS Identity)

I am trying to implement my own OAuth Server with IdentityServer4, and so far everything works except the logout.
I am not using Microsoft Identity, as I already have an existing WebApp with a WebApi which is handling the user-related CRUD operations. Thus I am using an existing Database for fetching Users and validating their username and PW. If validation is successful, my validation Method returns an object of type "AuthenticatedUser" (which is a UtilityClass I made).
Edit My Client is a Xamarin App, and using IdentityModel.OidcClient2 for login. I am testing with the UWP platform, Edit which uses WebAuthenticationBroker for Login/Logout calls.
Code I use is the one from the QuickStart UI Example, with a small modification to validate the users from my existing DB:
Edit Now I am explicitly creating Claims, ClaimsIdentity, and added CookieAuthenticationDefaults.AuthenticationScheme wherever possible.
//my method for user validation
AuthenticatedUser user = await _userService.ValidateCredentials(model.Username, model.Password);
//rest of login code from quickstart ui
if (user != null)
{
await _events.RaiseAsync(new UserLoginSuccessEvent(user.FirstName, user.Id.ToString(), user.FirstName));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
//things we know about the user that we wish to store on the cookie
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Role, user.RoleId.ToString()),
new Claim(JwtClaimTypes.Name, user.FirstName + " " + user.LastName),
new Claim(JwtClaimTypes.Subject, user.Id.ToString())
};
var userIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
//set the cookie using the SignInAsync method
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, props);
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.Id.ToString(), user.FirstName, props);
//....
So far, this seems to work well. When the Login fails, I cannot access my protected Api, if the login succeeds, I get an AccessToken with the claims I requested, and I can access the protected Api methods as expected.
When I call the logout endpoint (done by a HTTP request to the endpoint, providing id_token_hint as query parameter), though, for some reason the User is not Authenticated - therefore my User is never Logged out by calling HttpContext.SignOutAsync().
if (User?.Identity.IsAuthenticated == true) //always evaluates to false?! why?
{
// delete local authentication cookie
await HttpContext.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
Edit After using WebAuthenticationBroker instead of a simple HTTP Request for calling the logout endpoint, the console Logs though state that "XamarinApp" got logged out. Even though HttpContext.SignOutAsync() was never called What does this mean? I doubt that this is Ok, but the app behaves as I want afterwards, e.g I can log in with a new user.
[16:43:12 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /connect/endsession matched to endpoint type Endsession
[16:43:12 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Endsession, successfully created handler: IdentityServer4.Endpoints.EndSessionEndpoint
[16:43:12 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.EndSessionEndpoint for /connect/endsession
[16:43:12 Debug] IdentityServer4.Endpoints.EndSessionEndpoint
Processing signout request for anonymous
[16:43:12 Debug] IdentityServer4.Validation.EndSessionRequestValidator
Start end session request validation
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Start identity token validation
[16:43:12 Debug] IdentityServer4.EntityFramework.Stores.ClientStore
xamarinApp found in database: True
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Client found: xamarinApp / Xamarin App
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Calling into custom token validator: IdentityServer4.Validation.DefaultCustomTokenValidator
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Token validation success
{
//Token details omitted here for the sake of simplicity.
}
}
[16:43:12 Information] IdentityServer4.Validation.EndSessionRequestValidator
End session request validation success
{
"ClientId": "xamarinApp",
"ClientName": "Xamarin App",
"SubjectId": "unknown",
"PostLogOutUri": "xamarinformsclients://callback",
"Raw": {
"id_token_hint": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3RjlGQ0VFRTVCMzM4ODkzODZCNjc2MTZCRjZCOTFEMUEwRkRBQjAiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJCX244N3VXek9JazRhMmRoYV9hNUhSb1AyckEifQ.eyJuYmYiOjE1Mjg5MDA5ODYsImV4cCI6MTUyODkwMTI4NiwiaXNzIjoiaHR0cHM6Ly9sYXB0b3AtMW0waW4zMW46NDQzODciLCJhdWQiOiJ4YW1hcmluQXBwIiwibm9uY2UiOiI4YjZjZWRkMDFhMjQ0ZDJmOWY3ZGM4NzZmM2NmZGYwNiIsImlhdCI6MTUyODkwMDk4NiwiYXRfaGFzaCI6IkZualBtd2hiZTNmOVRITjEzM0NSZWciLCJzaWQiOiJkMmJlZTgyYzg0YWY2NGI5ZDUyYmZlNmExNmU1MTNmZiIsInN1YiI6IjI4IiwiYXV0aF90aW1lIjoxNTI4OTAwOTgzLCJpZHAiOiJsb2NhbCIsInVzZXJfaWQiOiIyOCIsInJvbGVfaWQiOiI0IiwibmFtZSI6IlRpbGwgU2F1YmVybWFubiIsImZhbWlseV9uYW1lIjoiU2F1YmVybWFubiIsImFtciI6WyJwd2QiXX0.ZjwL8nuq-WD3D-pXruZtE_I5TyNNO_ZMabz2JiKVnTaTnITwGV5CIJcLcWSpBCOyaSFXKUicAtROeWLReuk_LWoUTKXcX7lyv5VP9-ItBNA13EwgsbhQX7BgS2lbE9fQU7OgGARJcpvPKaT9FabFtEZsNYW9sNeBo-6CUPkYtVH_rjRyLihFi2NlZlkHBc7_oPE0hsjf61QIwyGZEhVXvDXkP_Q9t_Bfr3_QrUF6MfyhzLs0KcMwbtlWUxYw51J8phz7RPUXbbiZ1tG9Ay4DNy8RZbzfI-uFAbrqH7waLo_f5JO15eYc-xICl22ZS_4lW0_MlzP_rq46PnGOwNBqlg",
"post_logout_redirect_uri": "xamarinformsclients://callback"
}
}
Edit As far as I can understand, this probably has to do with my Xamarin Client and Cookies. I found tutorials on how to configure a MVC Client, IDSVR4 and the Cookie Middleware, but nothing regarding native Apps, IDSVR4 and Cookie Middleware.
How is IDSVR4 (or the logout in particular) supposed to work with a non-MVC Client and IdentityModel.OidcClient?
Finally I found the reason. In the QuickstartUI Examples, the Class "AccountConteroller.cs" sets Explicit Expiration only if the user chooses the "remember me" Option. I removed the if condition, and finally the authentication cookie is properly stored, on logout my user is not null anymore, and everything is fine.
class AccountController
...
AuthenticationProperties props = null;
//ALWAYS SET EXPLICIT EXPIRATION, SO COOKIE CAN BE DELETED WHEN LOGGING OUT
//if (AccountOptions.AllowRememberLogin && model.RememberLogin)
//{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
// };

Firebase Authentication (multiple types of users)

i am working on a react.js project which authenticate from firebase but i have 3 multiple type of user's in it (super Admin,vendor admin,vendor staff) with different privileges. how can i authenticate them from firebase and get to know this is my venor admin or vendor staff etc ???? because firebase just authenticate single type of user!
You can control access via custom claims using the Firebase Admin SDK on your own server of through Cloud Functions for Firebase.
Set claims server side for a specific bid with a method like this:
admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});
Then set up your database with a structure that separates admin and vendor admin content:
/
/admin
/data for admins here
/vendorAdmin
/ data for vendor admins here
/staff
// data for staff here, or perhaps this data is accessible to all since the admins may need access to it.
In the Firebase Console, customize the rules to restrict these locations to those who include the proper claim:
{
"rules": {
"admin": {
".read": "auth.token.admin === true",
".write": "auth.token.admin === true",
}
"vendorAdmin": {
".read": "auth.token.vendoradmin === true",
".write": "auth.token.vendoradmin === true",
}
"staff": {
".read": "auth.token.staff === true",
".write": "auth.token.staff === true",
}
}
}
This is a simplified example, so you'll have to customize it further to meet the needs of your app.
You can maintain a users table in your database, and every time you sign up a user just add them there as well, using the uid.

MSAL.JS version 0.1.3 single sign on

Related to MSAL.js
While using MSAL.js for single sign on for azure active directory, we use loginredirect method from MSAL to redirect user, it redirect to 'null' URL. I don't know why it happen but it come from MSAL library.
We use idtoken (new Msal.IdToken(localStorage["msal.idtoken"]);) method to decode token, when we use version 0.1.1 it works fine, when upgrade the version 0.1.3 it returns error "Msal.IdToken is not a constructor". I can't understand how to call the method.
One more issue with MSAL.js is, when we provide credential for login, login does not redirect to my application, I don't understand why it is looping in login page after entering correct credential.
When we logout and again try to login, it loop on login page.
We use 'if (errorDesc != null && errorDesc.indexOf("AADB2C90118") > -1) ' because we also do forgetpassword functionality.
Below the code which we implemented for redirection
var clientApplication = new Msal.UserAgentApplication(applicationConfig.clientID, applicationConfig.authority, authCallback, { cacheLocation: 'localStorage' });
function authCallback(errorDesc, token, error, tokenType) {
if (errorDesc != null && errorDesc.indexOf("AADB2C90118") > -1) {
clientApplication.authority = applicationConfig.passwordAuthority;
}
login();
}
function login() {
clientApplication.loginRedirect(applicationConfig.b2cScopes);
}
Please give me solution for this problems.
MSAL.js already takes care of expiracy, and the IDToken is used as a token cache key. It's not supposed to be used to get information about the user (if you want to do that, it's better to call the Microsoft Graph Me endpoint.
Also note that the IDToken is not signed, and therefore, in case of compromission of something on the line (chall you don't have a guaranty that its inf

Is user has active session on IDMsrv?

How to verify IDM does it have an active session for the user signing in?
details - If user'A' has a active session on IDM from browser 'X', When the same user 'A' try to login using browser 'Y', expected behavior identify that user has active session and invalidate the browser'X' session.
Background-
IDM with aspnetIdentity
Client with Implicit grant
(30 sec identitytoken life, does kept renewing access token silently without going to login page, expected to hit some method on the IDM then I can verify user has access or not)!!
Brock has already mentioned about it, It should be at the time of login and logout
It make sense,why its not in Idm. but its definitely possible to provide this as an enhanced feature at least in the coming versions.
Profile Service, IsActive method is the one hit by authorize and
tokenvalidation end point.
so at the time of login persist session, then when the above code hits do the check as per business requirement.
as long as the session is active ( cookie life time) the silent authentication will be passed with the application logic. so this can be controlled by cookie lifetime as well.
public override async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await userManager.FindByIdAsync(sub);
//Check existing sessions
if (context.Caller.Equals("AccessTokenValidation", StringComparison.OrdinalIgnoreCase))
{
if (user != null)
context.IsActive = !appuser.VerifyRenewToken(sub, context.Client.ClientId);
else
context.IsActive = false;
}
else
context.IsActive = user != null;
}
signin
public async Task<IActionResult> Login(LoginInputModel model)
{
if (ModelState.IsValid)
{
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberLogin, false);
if (result.Succeeded)
{
//Update security stamp to invalidate existing sessions
//TODO: This didn't invalidate the existing cookie from another client
//var test= _userManager.UpdateSecurityStampAsync(_userManager.FindByEmailAsync(model.Email).Result).Result;
appUser.PersistSession(new UserSession
{
CreatedOn = DateTimeOffset.Now,
DeviceUniqueId = GetDeviceId(),
UserId = _userManager.FindByNameAsync(model.Email).Result.Id,
SId = httpContext.HttpContext.Session.Id,
ClientId= httpContext.HttpContext.Request.QueryString.Value.GetClientIdFromQuery(),
ExpiresOn = DateTimeOffset.Now.AddMinutes(appSettings.SessionTimeOut)
});
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(model.ReturnUrl);
}
This method has a few drawback when IIS gets restarted and if user has not signed out properly.
there may be a better options this is not the best fit.!
Update:
refer here duplicate/similar question
idmsrv endpoints are missing security change check
Issue raised
Should be like this #tibold

Resources