Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keycloak - Multi/2FA Factor - OTP - QR Code - Custom Login Screen - Rest API

I have my own Login page where user enters username/password. This username/password are used to login through Keycloak Rest API.

http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token

input - {username,password,grant_type,client_secret,client_id}

And in response i get access token.

Now i wish to enable Authenticator (Google Authenticator). I have enabled it from backend. Now if user wishes to login thorugh my application, my login page i need to get below details.

1.) Somehow i need to include QR Code that appears on keycloak login page post username/password validation to show on my login screen for the first time login once user enter username/password. So do we have any API which return Keycloak QR code image in response.

2.) Subsequent login i will have OTP field, so need a REST api to pass OTP along with username/password.

Please help with REST API if keycloak has any. Integrating through Javascript.

Similar flow as described in use case 1 here

Just want to use keycloak as a database, doing all operation for me, input will be my screen. I do want redirection of URL's while login in and yet should be standalone deployed.

like image 319
Ankur Singhal Avatar asked Dec 17 '22 23:12

Ankur Singhal


1 Answers

I've managed to implement this through the rest API of Keycloak. To realize this, you need to extend Keycloak yourself with a SPI. To do this create your own Java project and extend org.keycloak.services.resource.RealmResourceProvider and org.keycloak.services.resource.RealmResourceProviderFactory. You can find more information in the official docs (https://www.keycloak.org/docs/latest/server_development/#_extensions), github examples and other stack overflow posts how to do this.

Once you got this up and running you can implement it like this:

@GET
@Path("your-end-point-to-fetch-the-qr")
@Produces({MediaType.APPLICATION_JSON})
public YourDtoWithSecretAndQr get2FASetup(@PathParam("username") final String username) {
    final RealmModel realm = this.session.getContext().getRealm();
    final UserModel user = this.session.users().getUserByUsername(username, realm);
    final String totpSecret = HmacOTP.generateSecret(20);
    final String totpSecretQrCode = TotpUtils.qrCode(totpSecret, realm, user);
    return new YourDtoWithSecretAndQr(totpSecret, totpSecretQrCode);
}

@POST
@Path("your-end-point-to-setup-2fa")
@Consumes("application/json")
public void setup2FA(@PathParam("username") final String username, final YourDtoWithData dto) {
    final RealmModel realm = this.session.getContext().getRealm();
    final UserModel user = this.session.users().getUserByUsername(username, realm);
    final OTPCredentialModel otpCredentialModel = OTPCredentialModel.createFromPolicy(realm, dto.getSecret(), dto.getDeviceName());
    CredentialHelper.createOTPCredential(this.session, realm, user, dto.getInitialCode(), otpCredentialModel);
}

The secret received with the GET must be send back with the POST. The initial code is the one from your 2FA app (e.g. Google Authenticator). The QR code is a string which can be displayed in an img with src 'data:image/png;base64,' + qrCodeString;

like image 97
Thomas Stubbe Avatar answered Jan 29 '23 07:01

Thomas Stubbe