Skip to main content

Multi-Factor Authentication

This page explains how to implement Multi-Factor Authentication (MFA) functionality using the SaaSus Auth API, based on the sample application's MFA settings feature.

Below is a screenshot of the multi-factor authentication settings dialog.

※This QR code is dummy data for demonstration purposes. It cannot be used for actual authentication.

The MFA functionality provides the following features:

  • Check MFA settings status
  • Register authentication applications (Google Authenticator, etc.)
  • Enable/disable MFA
  • Easy setup with QR codes

Frontend Implementation

Example Implementations

The following links point to repositories that include implementations of the frontend.

Backend Implementation

Endpoint Summary

TypeMethod & PathDescription
MFA Status CheckGET /mfa_statusRetrieves the user's MFA enabled/disabled status.
MFA SetupGET /mfa_setupGenerates QR code URL for authentication app registration.
MFA Code VerificationPOST /mfa_verifyVerifies authentication code from authentication app and registers MFA.
MFA EnablePOST /mfa_enableEnables MFA for the user.
MFA DisablePOST /mfa_disableDisables MFA for the user.
info

The following code samples assume Go for the backend.

MFA Status Check Endpoint

// Retrieve MFA status (enabled/disabled)
func getMfaStatus(c echo.Context) error {
// Retrieve user information from context
userInfo, ok := c.Get(string(ctxlib.UserInfoKey)).(*authapi.UserInfo)
if !ok {
c.Logger().Error("Failed to get user info")
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
}

// Use the SaaSus API to get the user's MFA status
response, err := authClient.GetUserMfaPreferenceWithResponse(context.Background(), userInfo.Id)
if err != nil || response.JSON200 == nil {
c.Logger().Errorf("failed to get MFA status: %v", err)
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve MFA status"})
}

// Return MFA enabled/disabled status
return c.JSON(http.StatusOK, map[string]bool{"enabled": response.JSON200.Enabled})
}

The following links contain implementations of this endpoint. Search for the function name to find the relevant section.

MFA Setup Endpoint

// Retrieve MFA setup information (generate QR code)
// The frontend application must include X-Access-Token in the request header
func getMfaSetup(c echo.Context) error {
// Retrieve X-Access-Token from the request header
accessToken := c.Request().Header.Get("X-Access-Token")
if accessToken == "" {
// Return authentication error if access token is missing
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Access token is missing"})
}

// Retrieve user information from context
userInfo, ok := c.Get(string(ctxlib.UserInfoKey)).(*authapi.UserInfo)
if !ok {
c.Logger().Error("failed to get user info")
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
}

// Use the SaaSus API to generate a secret code for MFA authentication app registration
response, err := authClient.CreateSecretCodeWithResponse(context.Background(), userInfo.Id, authapi.CreateSecretCodeJSONRequestBody{
AccessToken: accessToken,
})
if err != nil || response.JSON201 == nil {
c.Logger().Errorf("failed to create secret code: %v", err)
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to generate QR code"})
}

// Generate a QR code URL for Google Authenticator and other authentication apps
qrCodeUrl := "otpauth://totp/SaaSusPlatform:" + userInfo.Email + "?secret=" + response.JSON201.SecretCode + "&issuer=SaaSusPlatform"

// Return the QR code URL
return c.JSON(http.StatusOK, map[string]string{
"qrCodeUrl": qrCodeUrl,
})
}

The following links contain implementations of this endpoint. Search for the function name to find the relevant section.

MFA Authentication Code Verification Endpoint

// Verify the user's MFA authentication code
// The frontend application must include X-Access-Token in the request header
func verifyMfa(c echo.Context) error {
// Retrieve user information from context
userInfo, ok := c.Get(string(ctxlib.UserInfoKey)).(*authapi.UserInfo)
if !ok {
c.Logger().Error("Failed to get user info")
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
}

// Retrieve X-Access-Token from the request header
accessToken := c.Request().Header.Get("X-Access-Token")
if accessToken == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Access token is missing"})
}

// Retrieve the verification code from the request body
var requestBody struct {
VerificationCode string `json:"verification_code"`
}
if err := c.Bind(&requestBody); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request: malformed JSON or incorrect parameters"})
}
if requestBody.VerificationCode == "" {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Verification code is required"})
}

// Use the SaaSus API to register the authentication application
response, err := authClient.UpdateSoftwareTokenWithResponse(context.Background(), userInfo.Id, authapi.UpdateSoftwareTokenJSONRequestBody{
AccessToken: accessToken,
VerificationCode: requestBody.VerificationCode,
})
if err != nil || response.StatusCode() != http.StatusOK {
c.Logger().Errorf("MFA verification failed: Status Code %d, Response %s", response.StatusCode(), string(response.Body))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "MFA verification failed"})
}

return c.JSON(http.StatusOK, map[string]string{"message": "MFA verification successful"})
}

The following links contain implementations of this endpoint. Search for the function name to find the relevant section.

MFA Enable Endpoint

// Enable MFA for the user
func enableMfa(c echo.Context) error {
// Retrieve user information from context
userInfo, ok := c.Get(string(ctxlib.UserInfoKey)).(*authapi.UserInfo)
if !ok {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
}

// Create request body to enable MFA
method := authapi.SoftwareToken
requestBody := authapi.UpdateUserMfaPreferenceJSONRequestBody{
Enabled: true,
Method: &method,
}

// Use the SaaSus API to enable MFA
_, err := authClient.UpdateUserMfaPreferenceWithResponse(context.Background(), userInfo.Id, requestBody)
if err != nil {
c.Logger().Errorf("Failed to enable MFA: %v", err)
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to enable MFA"})
}

return c.JSON(http.StatusOK, map[string]string{"message": "MFA has been enabled"})
}

The following links contain implementations of this endpoint. Search for the function name to find the relevant section.

MFA Disable Endpoint

// Disable MFA for the user
func disableMfa(c echo.Context) error {
// Retrieve user information from context
userInfo, ok := c.Get(string(ctxlib.UserInfoKey)).(*authapi.UserInfo)
if !ok {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to retrieve user information"})
}

// Create request body to disable MFA
method := authapi.SoftwareToken
requestBody := authapi.UpdateUserMfaPreferenceJSONRequestBody{
Enabled: false,
Method: &method,
}

// Use the SaaSus API to disable MFA
_, err := authClient.UpdateUserMfaPreferenceWithResponse(context.Background(), userInfo.Id, requestBody)
if err != nil {
c.Logger().Errorf("Failed to disable MFA: %v", err)
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to disable MFA"})
}

return c.JSON(http.StatusOK, map[string]string{"message": "MFA has been disabled"})
}

The following links contain implementations of this endpoint. Search for the function name to find the relevant section.