I’m developing a Xamarin app that uses Azure AD B2C and I’m having some trouble getting data from any of the providers.
Even though I have LinkedIn, Google, Microsoft, Facebook, and Twitter setup as Identity Providers, and they appear to be configured properly, the only data returned is User.IdentityProvider. Both User.Name and User.DisplayableId are null. This happens for all of the providers.
Here is my call to AcquireTokenAsync:
var result = await App.AuthenticationClient.AcquireTokenAsync(Constants.Scopes, user, UIBehavior.SelectAccount, string.Empty, null, Constants.Authority, App.UiParent);
I have my application claims selected:
The login succeeds on every provider, but I don't get email addresses back like I need.
With help from a friend, I discovered that while the values in the User field are returned using Azure AD, the response from an Azure AD B2C call populates the IdToken field instead.
A bit more sleuthing turned up this to be a serialized JwtSecurityToken object. That led me to the following code:
var displayableId = ""; // result.User.DisplayableId;
var token = new JwtSecurityToken(result.IdToken);
foreach (var claim in token.Claims)
{
if (claim.Type == "emails")
{
displayableId = claim.Value;
}
}
Now displayableId contains the user's email address.
Related
Say you're using the built in AspNetCore Identity implementation.
To access some data a User must have the "CanFetchData" role. If they don't, a "Get Access" button is displayed which upon being clicked gives the User the Role and now they can see the data. Without Loggin Out. That's all I'm trying to do.
So onclick we:
var authState = await authenticationStateTask;
var currUser = await UserManager.GetUserAsync(authState.User);
await UserManager.AddToRoleAsync(currUser, "CanFetchData");
And now the Role is in the db. But the only way to update the view is to fully logout.
I've tried using StateHasChanged(); and SignInManager.RefreshSignInAsync(currUser) and a number of other approaches.
I realized that if I add the Claim directly it will update properly:
var newIdentity = new ClaimsIdentity();
newIdentity.AddClaim(new Claim(ClaimTypes.Role, "CanFetchData"));
authState.User.AddIdentity(newIdentity);
But is there no built in function to just refresh from the db?
I'm new to next-auth, and I'm looking for some help.
I have added the Google OAuth provider, and now when I run signIn("google") function on the frontend, it automatically takes me to the google's login page, and logs me in, somehow, without ever touching my database.
When the google authentication is complete, I need to be able to create a new user in my database, or retrieve the existing one if they have already signed up before (because I need to store all kinds of custom information about the user, not just their email).
And I want to make user's information available on the session object from useSession()hook. Right now I'm seeing some kind of default user info (with name, email, and image field which I didn't define).
When I was using a regular Express server and Passport, the code looked kinda like this:
const googleAuth = new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/api/v1/profiles/google/callback",
},
async (req, accessToken, refreshToken, profile, done) => {
const existingProfile = await Profile.findOne({ email: profile.emails[0].value })
/* Found user, return him and move along. */
if (existingProfile) return done(null, existingProfile)
/* Haven't found profile with this googleId, create a new one. */
const newProfile = await new Profile({
googleId: profile.id,
email: profile.emails[0].value,
})
newProfile.save()
done(null, newProfile)
}
)
So I would still be creating the users in my database, and retrieving their information on log in, so that I could send it to the client.
Where does this kind of code supposed to go when I'm using the serverless next-auth?
And a second, but kind of related question - what's that default user object that gets provided to me in the session object? The one with the name, email, and image fields that next-auth seems to create for me? How can I make it use the user object I'm returning from my database instead?
(I've done my best to look through the tutorials and examples, but couldn't find one that explains this clearly.)
I don't know if you still need this, but I hope it helps someone:
Oauth kinda mixes up Sign In and Sign Up, so if you want to have Google authentication what you probably want to do is create a callback of the Sign In function in /api/auth/[...nextauth].js, then get the account and profile as parameters and access to its provider.
async signIn({account, profile}) {
if(account.provider === 'google') {
//check if user is in your database
if(user NOT in DB) {
//add your user in DB here with profile data (profile.email, profile.name)
}
return true
}
You always want to return true since you always want to log in independently if it is in your DB or not.
Regarding the session object, you can also add a callback and access to the default session (that you can modify), token and user. Here you can retrieve all information you want from your database, add it to the session object and return it.
async session({ session, token, user }) {
const newData = DB.find(...).data
session.newfield = newInfo
return session
}
I use ASP.NET Identity 2 in an MVC 5 project and there are some users in AspNetUsers table. Although these users have been created and validated, it is impossible to retrieve any of them bu using:
var user = await UserManager.FindByNameAsync(model.Email);
Please note that I used email addressed for UserName as Email fields and it is ok to use email address for retrieving users.
On the other hand, I can retrieve the users by:
ApplicationUser user = db.Users.FirstOrDefault(m => m.Email == model.Email);
But, I cannot make sign-in the user with the following code and the result is always Failure.
var result = await SignInManager.PasswordSignInAsync(user.Email,
model.Password, model.RememberMe, shouldLockout: false);
Any idea to fix the problem?
Assuming I want to create users upon authorizing the app, how would I grab their email during the onAuth callback...? Looks like the callback assumes the user is already logged in. Am I thinking about it correctly?
I noticed when installing the Fishbowl Prizes app, after auth I can click on the accounts tab and see that all my account info is pre-populated from my shopify store account (name, email, address, etc).
I'm not sure if I should go by the title or the content of the post in terms of answering your question, so I'll provide a very simple example of how to get the info from the API and do something with it here.
I have provided a more in depth answer related specifically to grabbing the details from the API for user account creation here: https://github.com/froatsnook/meteor-shopify/issues/15#issuecomment-177413630
Looks like the callback assumes the user is already logged in.
The userId param is undefined if there is no user. If your onAuth operations don't need to do anything with the user, you can just leave it out of the params. In your case you'll just want to handle it conditionally using an if/else block:
if(!userId){
// do stuff
} else {
// do other stuff
}
On to the example of grabbing those details from the API:
All the prepopulated information you are seeing is available from the Shopify API in the shop object. You already have the access token when onAuth callbacks are fired, so you can just grab it from the API immediately after you have inserted the shop's Keyset.
For the sake of simplicity, in this example we'll assume the user already exists and is logged in. In your server-side onAuth callback (after you have inserted the keyset) you can do something like this to add those fields to the user's profile object:
Shopify.onAuth(function(access_token, authConfig, userId) {
var shopUUID = uuid.new(); // Not secure to name keyset same as the shop!
Shopify.addKeyset(shopUUID, {
access_token: access_token
});
var api = new Shopify.API({
shop: authConfig.shop,
keyset: shopUUID
});
// get the Shop object from the API
var shopObj = api.getShop();
var userInfo = {
'profile.name': shopObj.shop_owner,
'profile.email': shopObj.email,
'profile.phone': shopObj.phone,
'profile.shopName': shopObj.name
};
Meteor.users.update({_id: userId}, {$set: userInfo})
});
Then you can use them in templates like this:
{{currentUser.profile.name}} or {{currentUser.profile.email}}
Or in functions like so:
var realName = Meteor.user().profile.name
or
var userEmail = Meteor.user().profile.email etc
For a more about using this data for user creation, see my explanation here:
https://github.com/froatsnook/meteor-shopify/issues/15#issuecomment-177413630
It's easy to get the simple login working with Twitter, and that's a big bonus, but I was wondering whether it's possible to then take those authentication credentials and post a tweet, get a list of people they're following, generally use the full Twitter 1.1 API. I.e. can I get hold of the access token key and secret?
Thanks,
Dave.
The Firebase Simple Login JavaScript client now returns both the Twitter access token and access token secret in the response payload from Twitter authentication.
You can access each of these via the user object, under the attributes accessToken and accessTokenSecret as shown below:
var firebaseRef = new Firebase('https://<MY-FIREBASE-NAME>.firebaseIO.com');
var authClient = new FirebaseAuthClient(firebaseRef, function(error, user) {
if (user) {
var accessToken = user.accessToken,
accessTokenSecret = user.accessTokenSecret;
}
});
...
// Sample jQuery click event.
$myButton.on('click', function(event) {
authClient.login('twitter');
});