RobThree / TwoFactorAuth.Net

.Net library for Two Factor Authentication (TFA / 2FA)
MIT License
338 stars 59 forks source link

optauth Uri not fully compatible with Microsoft Authenticator #17

Open unsprung opened 4 years ago

unsprung commented 4 years ago

Microsoft Authenticator ignores the issuer when it is included in the querystring portion of the Uri. In this case it takes only the label.

This can be fixed by including the issuer/service provider before the label in path portion of the Uri as described here: https://github.com/google/google-authenticator/wiki/Key-Uri-Format

eg. otpauth://totp/Example: alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example

I've only tested with Microsoft Authenticator and Google Authenticator, but they both work with this format.

RobThree commented 4 years ago

You can use the label argument of the GetQrText or GetQrCodeImageAsDataUri methods.

Though I must admit I apparently have missed the 'If both issuer parameter and issuer label prefix are present, they should be equal.' part. I should look into that; I'm not sure if any of the TOTP apps treat both differently. Since it's specified as should instead of must I will, for now, keep treating them as two different things which may differ.

unsprung commented 4 years ago

Yes, I tried setting the label to the same thing as the issuer, and while this works for Microsoft Authenticator, it will then of course show this for both which isn't ideal since you don't get the differentiation between them. That is why I described it as not fully compatible since it "works" no matter what, but the display in the app is then not ideal.

To test/fix this I created a new class that inherits from TwoFactorAuth then overwrote the base implementations of GetQrText (changed) and GetQrCodeImageAsDataUri (unchanged) using the new keyword. When providing the Uri from GetQrText as decribed above, it then worked as expected in Microsoft Authenticator and also still in Google Authenticator.

If you don't want to update the Uri produced by GetQrText for compatibility reasons, then consider marking it as virtual to make it easier to override the implementation as necessary.