Issuer label on QR code for 2FA not showing correct value - two-factor-authentication

I am using speakeasy library and qrcode library, to generate an otpauth URL and then transforming it into a QR code, so this can be scanned by an authenticator app for 2FA on my website.
I want the authenticator apps to show my website in the following format:
Test Company (<-- the name of my website)
test#fakemail.com (<-- the email of the user)
My code to generate the url is:
let url = speakeasy.otpauthURL({ secret: secret.base32, label: userEmail, issuer: 'Test Company', encoding: 'base32' })
This generates a URL like so:
otpauth://totp/test#fakemail.com?secret=ENTEWOKSHQRXQ4CYGBREYWDVFRTGYVRXNF2FWSBRKE7SUOJZGY4Q&issuer=Test%20Company
And then I transform it to a QR code like so:
let qrImageUrl = await qrcode.toDataURL(url)
I now try to set up 2FA with my user with email address "test#fakemail.com". It seems it takes the first part of the email domain as the issuer.
The result in Microsoft Authenticator app looks like this:
fakemail
test#fakemail.com
But when I scan this exact same code in Google Authenticator app, it shows me (on one line):
Test Company (test#fakemail.com)
When changing the code to contain a colon like so:
let url = speakeasy.otpauthURL({ secret: secret.ascii, label: `Test Company:${userEmail}` })
In microsoft authenticator app it will now show perfectly like so:
Test Company
test#fakemail.com
But in Google authenticator app, it shows in one line with the semi colon literally in there:
Test Company:test#fakemail.com
What is the correct approach to have every single authenticator app in the exact same format?

Try pass all the possibilities combined into the same request.
Normally the application itself will use the most applicable variables and will show accordingly in the specific app.
let url = speakeasy.otpauthURL({ secret: secret.base32, label: `Test Company:${userEmail}`, issuer: 'Test Company', encoding: 'base32' })

Related

Why does Microsoft Authenticator show email domain when using email as label rather than the Issuer?

I am using TwoFactorAuth.net to show a QR code for scanning into an authenticator app. This works if I use a name in the "label" parameter. However, if I use an email address as the "label" in creating the QR code, Microsoft Authenticator uses the domain from the email as the Issuer, rather than the provided issuer.
To wit:
EX 1 - Not Email (i.e. sample code):
private readonly TwoFactorAuth tfa = new TwoFactorAuth("MyCompany",
qrcodeprovider: new QRCoder.QRCoderQRCodeProvider());
Model.GetQrCodeImageAsDataUri("Bob Ross", (string)Session["secret"])"
RESULT:
EX 2 - Email Label:
private readonly TwoFactorAuth tfa = new TwoFactorAuth("MyCompany", qrcodeprovider: new QRCoder.QRCoderQRCodeProvider());
img src="#Model.GetQrCodeImageAsDataUri("mypaint#thebobross.com", (string)Session["secret"])"
RESULT:
However, the email DOES work properly in Google Authenticator:
Any ideas?
Here's the standard Key Uri Format:
otpauth://TYPE/LABEL?PARAMETERS
I couldn't find any substantial information on how Microsoft Authenticator parses otpauth URI but after testing different ways I have come to the conclusion that if an email address alone is given as a LABEL, Microsoft Authenticator picks the subdomain of whatever TLD is present. Actually, Wiki also says different parts of a domain name are called labels so probably that's the logic there.
Anyway, I solved it by adding Issuer before the email address as LABEL (mind the ':' separator).
"MyCompany:mypaint#thebobross.com"
I've successfully tested this with Microsoft and Google Authenticator. Both show MyCompany as LABEL.

Firebase Auth: Is it possible to see user's Twitter ID?

I have just implemented the Twitter login to my Firebase web app. When the user successfully login, I'd like to see the user's Twitter ID (to enable Twitter-based communication among users).
According to the document (https://firebase.google.com/docs/auth/web/manage-users), the provider specific information is under providerData of the user info.
Under the providerData, I see the following
displayName: "Satoshi Nakajima" (as I expected)
email: null (as I expected)
phoneNumber: null (as I expected)
photoURL: "https://abs.twimg.com/..." (as I expected)
providerId: "twitter.com" (of course)
uid: "1129128..." (what is this?)
The uid seems like a unique id, but it is different from the Twitter ID we usually use, such as #snakajime (which is mine).
I am wondering why I don't see the Twitter id here. Am I missing something? Is there any API to get the Twitter ID from this strange uid?
You can actually get it immediately after sign-in, via AdditionalUserInfo.
Here is an example with the web API:
firebase.auth().signInWithPopup(new firebase.auth.TwitterAuthProvider())
.then((userCredential) => {
// Get the Twitter screen name.
console.log(userCredential.additionalUserInfo.username);
})
.catch((error) => {
// An error occurred.
});
As far as I know, the screen name you are looking for is not included as part of the Twitter OAuth provided through Firebase, but the uid that you have found is indeed the user's twitter user ID.
Using this ID you can use the Twitter API to get details about the user by passing it to the twitter API users/show endpoint. Since you plan on providing Twitter based communication, you will likely need to use this API anyway.
e.g.:
GET https://api.twitter.com/1.1/users/show.json?user_id={the_uid_from_provider_data}
RESPONSE:
{
"id": {the_uid_from_provider_data},
"id_str": "{the_uid_from_provider_data}",
"name": "Snakajime",
"screen_name": "snakajime", // <--- Here is the screen name you are looking for
...
}

Adding a button for google signin using f#/fable/asp.net/react

I'm working with the SAFE stack (https://safe-stack.github.io/) and through the example dojo. It's great so far.
I'd like to extend the example to include a button to login/auth via Google. So I looked at an example on the Google website (https://developers.google.com/identity/sign-in/web/build-button). And then I had a look how to do authentication using ASP.NET (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-2.1&tabs=aspnetcore2x) As a result I ended up confused as to how to integrate this into a SAFE project. Can someone tell me what they would do? SHould I be trying to use ASP.NET Identity or should I be using the JWT approach? I don't even know if they are the same since I'm very new to web frameworks.....
The other question I have is how would one inject raw Javascript into the client side of a SAFE project. The google example above shows raw JS/CSS/HTML code? Should I be injecting that as is or should I look in React for some button that does this and map that idea back through Fable?
Setting up OAuth
The easiest way to use Google OAuth is to wait until the next release of Saturn, at which point Saturn will include the use_google_oauth feature that I just added. :-) See the source code if you're interested in how it works, though I'm afraid you can't implement this yourself with use_custom_oauth because you'll run into a type error (the underlying ASP.NET code has a GoogleOptions class, and use_custom_oauth wants an OAuthOptions class, and they aren't compatible).
To use it, add the following to your application CE:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" []
The last parameter should be a sequence of string * string pairs that represent keys and values: you could use a list of tuples, or a Map passed through Map.toSeq, or whatever. The keys of that sequence are keys in the JSON structure that Google returns for the "get more details about this person" API call, and the values are the claim types that those keys should be mapped to in ASP.NET's claims system. The default mapping that use_google_oauth already does is:
id → ClaimTypes.NameIdentifier
displayName → ClaimTypes.Name
emails[] (see note) → ClaimTypes.Email
Those three are automatically mapped by ASP.NET. I added a fourth mapping:
avatar.url → `"urn:google:avatar:url"
There's no standard ClaimTypes name for this one, so I picked an arbitrary URN. Caution: this feature hasn't been released yet, and it's possible (though unlikely) that this string might change between now and when the feature is released in the next version of Saturn.
With those four claim types mapped automatically, I found that I didn't need to specify any additional claims, so I left the final parameter to use_google_oauth as an empty list in my demo app. But if you want more (say you want to get the user's preferred language to use in your localization) then just add them to that list, e.g.:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" ["language", "urn:google:language"]
And then once someone has logged in, look in the User.Claims seq for a claim of type "urn:google:language".
Note re: the emails[] list in the JSON: I haven't tested this with a Google account that has multiple emails, so I don't know how ASP.NET picks an email to put in the ClaimTypes.Email claim. It might just pick the first email in the list, or it might pick the one with a type of account; I just don't know. Some experimentation might be needed.
Also note that third-party OAuth, including GitHub and Google, has been split into a new Saturn.Extensions.Authorization package. It will be released on NuGet at the same time that Saturn's next version (probably 0.7.0) is released.
Making the button
Once you have the use_google_oauth call in your application, create something like the following:
let googleUserIdForRmunn = "106310971773596475579"
let matchUpUsers : HttpHandler = fun next ctx ->
// A real implementation would match up user identities with something stored in a database, not hardcoded in Users.fs like this example
let isRmunn =
ctx.User.Claims |> Seq.exists (fun claim ->
claim.Issuer = "Google" && claim.Type = ClaimTypes.NameIdentifier && claim.Value = googleUserIdForRmunn)
if isRmunn then
printfn "User rmunn is an admin of this demo app, adding admin role to user claims"
ctx.User.AddIdentity(new ClaimsIdentity([Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, "MyApplication")]))
next ctx
let loggedIn = pipeline {
requires_authentication (Giraffe.Auth.challenge "Google")
plug matchUpUsers
}
let isAdmin = pipeline {
plug loggedIn
requires_role "Admin" (RequestErrors.forbidden (text "Must be admin"))
}
And now in your scope (NOTE: "scope" will probably be renamed to "router" in Saturn 0.7.0), do something like this:
let loggedInView = scope {
pipe_through loggedIn
get "/" (htmlView Index.layout)
get "/index.html" (redirectTo false "/")
get "/default.html" (redirectTo false "/")
get "/admin" (isAdmin >=> htmlView AdminPage.layout)
}
And finally, let your main router have a URL that passes things to the loggedInView router:
let browserRouter = scope {
not_found_handler (htmlView NotFound.layout) //Use the default 404 webpage
pipe_through browser //Use the default browser pipeline
forward "" defaultView //Use the default view
forward "/members-only" loggedInView
}
Then your login button can just go to the /members-only route and you'll be fine.
Note that if you want multiple OAuth buttons (Google, GitHub, Facebook, etc) you'll probably need to tweak that a bit, but this answer is long enough already. When you get to the point of wanting multiple OAuth buttons, go ahead and ask another question.

Facebook login scope: public_profile object not returning picture, cover, age_range

I provide a Facebook login button on my website.
I'm querying Facebook api v2.8 and try to access a user's picture, age_range and cover profile fields, which should be provided in the default public_profile object: https://developers.facebook.com/docs/facebook-login/permissions/
When connecting to my Facebook app I'm using this in my URL to determine scope: This works fine (but does not return picture,age_range,cover fields):
https://www.facebook.com/v2.8/dialog/oauth?client_id=<MYCLIENTID>&redirect_uri=https://www.example.com/login.aspx?loggedin=true&scope=email
But I'm getting only this returned:
{"id":"734565845333","email":"flo\u0040outlook.com","first_name":"Flo","gender":"male","last_name":"Unknown","link":"https:\/\/www.facebook.com\/app_scoped_user_id\/734565845333\/","locale":"en_US","name":"Flo Unknown","timezone":5,"updated_time":"2017-04-30T10:46:29+0000","verified":true}
I checked here: Satellizer Facebook login not returning the right scope and here Facebook JS SDK's FB.api('/me') method doesn't return the fields i expect in Graph API v2.4+, where it's suggested to add the fields to the scope, but when I try:
&scope=email,picture,age_range,cover,public_profile or &scope=email,picture,age_range,cover Facebook returns a 500 error.
e.g.:
https://www.facebook.com/v2.8/dialog/oauth?client_id=<MYCLIENTID>&redirect_uri=https://www.example.com/login.aspx?loggedin=true&scope=email,picture,age_range,cover
Why are the other fields not returned?

How to reset password in meteor application

I am building a Meteor application and am using the oaf:accounts-entry package to handle my user registration & authentication. I am working on the reset password function right now. However, when I click on "email reset password link", the application doesn't email me anything. Can someone help me or point me to instructions on how to configure the reset password function for the oaf:accounts-entry package? After doing a google search, I could not find instructions on how to configure it. The relevant packages I have installed are:
oaf:accounts-entry
accounts-password
email
Thank you!!
The password reset functionality should be working as it's provided by the package.
Have you properly configured your emails smtp settings and tested that your application is dispatching emails properly?
https://gentlenode.com/journal/meteor-3-smtp-configuration/5
NOTE: Using Meteor JS 1.6.1.1, package required are accounts-ui, accounts-password
To make forgot password link visible in the signup/sign in a widget, you need to do add little configuration in a file at location ROOT_FOLDER/client/main.js. The code is as below,
Accounts.ui.config({
passwordSignupFields: "USERNAME_AND_EMAIL"
});
If you do not choose passwordSignupFields: "USERNAME_AND_EMAIL" and choose something like passwordSignupFields: "USERNAME_ONLY", you won't be able to see forgot password option in the signup widget. (No one will tell you this, I discovered this weird scenario myself. Still, I wonder why MDG team did this? )
At Server end you also need to add little code at location PROJECT/server/main.js just outside Meteor.startup(()=>{}); to provide an email template for reset password link. Below is the code you need to adjust some properties yourself.
var username = 'you_id#gmail.com';
var password = 'your password';
var server = 'smtp.gmail.com';
var port = '465';
process.env.MAIL_URL = 'smtps://' +
encodeURIComponent(username) + ':' +
encodeURIComponent(password) + '#' +
encodeURIComponent(server) + ':' + port;
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
Accounts.emailTemplates.from = 'support_team#yourappname.com';
Accounts.emailTemplates.siteName = 'APP NAME';
Accounts.emailTemplates.resetPassword = {
subject(user) {
return "Reset Password Link.";
},
text(user, url) {
return `Hello!
Click the link below to reset your password.
${url}
If you didn't request this email, please ignore it.
Thanks,
APP Team.
`
},
html(user, url) {
// This is where HTML email content would go.
// See the section about html emails below.
}
};
STEP 1:
See if you are able to view forgot password on the signup widget as below.
STEP 2:
When you click "forgot password", you should be able to view below popup at same widget location as below.
on valid Email entry, you must see a success full notification and most importantly you must receive a mail for reset password link as below.
Step 3:
When you click on the link, you can see a new window with a popup as below (NOTE: You must click the link before given token expiry time).
Voila!!! just add a new password and you automatically login to given page. Everything is already provided to us as discussed above by Meteor. You just need to configure the stuff and get it running.

Resources