This example uses Austin Delamar's JOTP: https://github.com/amdelamar/jotp I found it to be the easiest to use, but others should produce the same results.
Run the app with ./mvnw spring-boot:run
then browse to http://localhost:8080.
When the app is running, the in-memory DB can be inspected at http://localhost:8080/h2-console (credentials).
This is, of course, a proof of concept and should not be deployed publicly.
TOTP-based 2FA works like this:
- Each user needs a secret key which is generated when they create their account.
- After the account is created, the key is shared with the user in the form of a QR code which creates an account in their authenticator app.
- When a user tries to log in they have to provide the 6-digit number from their app, which is calculated from the secret and the current time.
- The same calculation happens server-side to verify that the user possesses the secret key.
The version of this app which does not have 2FA is in this repo, tagged without-2fa. The 2FA-enabled version (ie this version) is in the totp-2fa tag
- Add a
superSecretSecret
field toUserDto
. [source] - Set the
superSecretSecret
inUserService#createNewUser
by callingOTP.randomBase32(20)
. [source] - Add steps to the account creation flow, with a new page showing the QR code, and configuration in
WebController
. [source] [template]
- Create
TwoFAAuthenticationProvider
extendsDaoAuthenticationProvider
, which checks the auth details in theauthenticate
method. [source] - Create a
TwoFAAuthenticationDetailsSource
, which implementsAuthenticationDetailsSource
, essentially just a factory for the above. [source] - Add that into
WebSecurityConfig
(which extendsWebSecurityConfigurerAdapter
and is annotated@Configuraion
and@EnableWebSecurity
). [source] - Make sure to require
.authenticated()
on any resources that need a logged-in user. [source]