If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOkay, status check. Any user can now enable two-factor authentication on their account by clicking this link. Behind the scenes, when they do that, we populate the totpSecret
on the User
object, save that to the database, and then render a QR code the user can scan. This QR code is a fancy image that contains two pieces of information. The first is the email of our user. Or, more precisely, if I scroll down to the "totp methods" in User
, it contains whatever we return from getTotpAuthenticationUsername()
:
... lines 1 - 20 | |
class User implements UserInterface, PasswordAuthenticatedUserInterface, TwoFactorInterface | |
{ | |
... lines 23 - 250 | |
public function getTotpAuthenticationUsername(): string | |
{ | |
return $this->getUserIdentifier(); | |
} | |
... lines 255 - 266 | |
} |
The second thing the QR code image contains is the totpSecret
. In a minute, I'm going to scan this code with an authenticator app, which will allow me to generate the correct two-factor authentication code that I'll need to log in. It does that by leveraging that secret.
But first, there is some extra info that we can add to the QR code. Head over to config/packages/scheb_2fa.yaml
. Under totp:
, one of the most important things that you can add is called an issuer
. I'm going to set this to Cauldron Overflow
:
# See the configuration reference at https://github.com/scheb/2fa/blob/master/doc/configuration.md | |
scheb_two_factor: | |
... lines 3 - 8 | |
totp: | |
... line 10 | |
issuer: 'Cauldron Overflow' |
That literally just added new information to the QR code image. Watch the image when we refresh. See that? It changed!
Thanks to this, in addition to the email
and totpSecret
, the code now contains an "issuer" key. If you want to learn about all the extra information that you can put here, check out the documentation or read about totp authentication in general. Because, for example, "issuer" is just a "totp concept"... that helps authenticator apps generate a label for our site when we scan this code.
At this point, I want to pretend that we're a real user and test the entire flow. If we were a real user we would pull out our phone, open an authenticator app - like Google authenticator or Authy - and scan this code.
I like using Authy, here's what it looks like for me. I add a new account, scan and... got it! It reads my email and the "issuer" from the QR code and suggests a name and logo. If your company is well-known, it might actually guess the correct logo, but you can also add an image
to your QR code in the same way that we added the “issuer”. When I accept this, it gives me codes!
So we are ready! Let's try it! Log out... and then log back in with abraca_admin@example.com
, password tada
. Submit and... sweet! Instead of actually being logged in, we're redirected to the two-factor authentication page! This happened for two reasons. First, the user has two-factor authentication enabled on their account. Specifically, this isTotpAuthenticationEnabled()
method returned true. Second, the security "token" - that internal thing that wraps your User
object when you log in - well, it matches one of the tokens in our configuration. Specifically, we get the UsernamePasswordToken
when we log in via the form_login
mechanism.
If we try going anywhere else on the site, it kicks us right back here. The only place we can go to is /logout
if we wanted to cancel the process. This is because the two-factor bundle will now deny access to any page on our site unless you've explicitly allowed it via the access_control
rules, like we did for /logout
and for the URL showing this form. This form is ugly, but we'll fix that soon.
Ok, back to pretending I'm a real user. I'll open up my authenticator app, type in a valid code: 5, 3, 9, 9, 2, 2 and... got it! We're logged in! So cool!
Next, let's customize that two-factor authentication form... because it was ugly.
Hey @Soufiyane!
Hmmm. Ok, so once you've got the bundle installed and configured, when you log in, the bundle calls the ->isTotpAuthenticationEnabled()
method on your User
object. If this returns true, it should redirect to the QR code page. If it returns false
, it will not do that. So that's the first place to look: triple-check that this method IS returning true for your user. If it is, let me know, and we can debug further - it would likely be some sort of missing configuration related to the bundle :).
Cheers!
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.3", // v3.3.0
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"doctrine/annotations": "^1.0", // 1.13.2
"doctrine/doctrine-bundle": "^2.1", // 2.6.3
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.1.1
"doctrine/orm": "^2.7", // 2.10.1
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"knplabs/knp-time-bundle": "^1.11", // v1.16.1
"pagerfanta/doctrine-orm-adapter": "^3.3", // v3.3.0
"pagerfanta/twig": "^3.3", // v3.3.0
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"scheb/2fa-bundle": "^5.12", // v5.12.1
"scheb/2fa-qr-code": "^5.12", // v5.12.1
"scheb/2fa-totp": "^5.12", // v5.12.1
"sensio/framework-extra-bundle": "^6.0", // v6.2.0
"stof/doctrine-extensions-bundle": "^1.4", // v1.6.0
"symfony/asset": "5.3.*", // v5.3.4
"symfony/console": "5.3.*", // v5.3.7
"symfony/dotenv": "5.3.*", // v5.3.8
"symfony/flex": "^1.3.1", // v1.17.5
"symfony/form": "5.3.*", // v5.3.8
"symfony/framework-bundle": "5.3.*", // v5.3.8
"symfony/monolog-bundle": "^3.0", // v3.7.0
"symfony/property-access": "5.3.*", // v5.3.8
"symfony/property-info": "5.3.*", // v5.3.8
"symfony/rate-limiter": "5.3.*", // v5.3.4
"symfony/runtime": "5.3.*", // v5.3.4
"symfony/security-bundle": "5.3.*", // v5.3.8
"symfony/serializer": "5.3.*", // v5.3.8
"symfony/stopwatch": "5.3.*", // v5.3.4
"symfony/twig-bundle": "5.3.*", // v5.3.4
"symfony/ux-chartjs": "^1.3", // v1.3.0
"symfony/validator": "5.3.*", // v5.3.8
"symfony/webpack-encore-bundle": "^1.7", // v1.12.0
"symfony/yaml": "5.3.*", // v5.3.6
"symfonycasts/verify-email-bundle": "^1.5", // v1.5.0
"twig/extra-bundle": "^2.12|^3.0", // v3.3.3
"twig/string-extra": "^3.3", // v3.3.3
"twig/twig": "^2.12|^3.0" // v3.3.3
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
"symfony/debug-bundle": "5.3.*", // v5.3.4
"symfony/maker-bundle": "^1.15", // v1.34.0
"symfony/var-dumper": "5.3.*", // v5.3.8
"symfony/web-profiler-bundle": "5.3.*", // v5.3.8
"zenstruck/foundry": "^1.1" // v1.13.3
}
}
when i try to log in, they don't take me to the page where i need to insert the code from QR-Code, please help