If your application needs conditional access based on the user’s country, you can easily achieve it with a simple Auth0 Action. Let’s see how you can do it.
Why a Country-based Login?
Controlling user access based on the country where they're located when they log in to your application may have different reasons. To mention just a few of them:
- Legal reasons. Laws are different around the world. This leads to adapting access to services or content offered by your application so that it does not break the laws of a particular country. For example, think of online gambling: it is illegal in some countries. Also, think of the liability requirements of GDPR for Europe: you must comply with them in order to offer your services to European citizens.
- Business reasons. A company may decide not to offer their services or product to a country for business reasons: maybe because the cost of delivering that product or service in a given country is not affordable, or because the pricing strategy may depend on the country. You can even consider copyright licenses: think of the availability of video on-demand services due to copyright restrictions, for example.
- Security reasons. You may consider accesses coming from a given country dangerous because most traffic is statistically malicious.
Depending on the reason you want to control user access and on the services or content offered by your application, you can apply different restriction levels. You can range from blocking access to your application (geo-blocking) to adapting your services or content to that country's audience.
Be aware that the most common technique to geolocate a user is based on their IP address. However, blocking users based on their IP address can be easily circumvented through VPNs or anonymizer services.
Using Auth0 Actions
This article will focus on how you can use Auth0 Actions to detect the user's country and how to block them or require a second authentication factor. Auth0 Actions are JavaScript functions running in a Node.js environment executed when specific events happen in a few internal Auth0 Flows, such as the Login Flow, the Change Password Flow, the User Registration Flow, etc.
Each Flow is made up of one or more triggers. For example, the Login Flow runs when a user logs in. This Flow has a post-login trigger: an event fired after the user logs in. You can handle this event through one or more Actions. You can think of Actions as event handlers that run when a specific event fires in an Auth0 Flow.
The following is a graphical representation of an Action (AddRoles) that will be executed in the Login Flow after the user logs in:
In the following, you will use the post-login trigger of the Login Flow to detect the user's country and apply your control strategy.
To learn more, you can check out this blog post for a quick introduction to Auth0 Actions.
Blocking Logins from a Country
Let's assume you want to block users coming from a given country. As I said, you need to create an Auth0 Action to handle the post-login trigger. So, head to your Auth0 dashboard. If you don't have an Auth0 account yet, you can sign up for a free one.
Select Actions on the left side menu and then Flows. You should land on the following page:
Click the Login Flow and enter the Flow editor, as shown below:
Here, you can add a custom Action by clicking the Build Custom menu item in the Add Action section of the Flow editor:
This allows you to assign a name to the Action you are going to create and to access the Action editor:
Replace the code in the editor with the following:
exports.onExecutePostLogin = async (event, api) => { if (event.request.geoip.countryCode === "AQ") { const countryName = event.request.geoip.countryName; api.access.deny(`Users from ${countryName} are not allowed!`); }; };
This code defines the
onExecutePostLogin()
method, which handles the post-login trigger. It receives two parameters: event
and api
.The
event
parameter provides some information about the current running environment. For example, it allows you to access the current user's data, the current request, the tenant, etc. For more details about the Pre User Registration event
object, check out the documentation.The
api
parameter provides methods for changing the behavior of the Flow. For example, it allows you to deny access to your application or set specific metadata for the user or the application. For more details about the Pre User Registration api
object, check out the documentation.In your Action, you used the
event.request.geoip
object to get geolocation information about the user logging in. In particular, you checked the countryCode
property, which can have one of the ISO country codes as a value. In the example, you want to block users coming from Antarctica, whose country code is AQ
. The geoip
object also provides you with other information about the user's country. For example, you used the countryName
property to get the full name of the country. Check out the post-login event
object documentation for more details.If the user's country is Antarctica, access is denied through the
api.access.deny()
method. The string passed to the deny()
method briefly explains the reason for the denied access.Click the Save Draft button to store the Action you just created.
To test this Action, you should... move to Antarctica and try to log in to your application from there. This approach is a bit expensive and ineffective 🙂. Alternatively, you can test the Action by using the Test button on the upper-left corner of the Action editor. It opens a sliding window whose content is the
event
object that will be passed to the Action:You can modify the
geoip
object's properties to simulate a request coming from Antarctica and click the Run button. At this point, you will get a window showing a result similar to the following:Requesting MFA from a Country
In addition to or instead of blocking users, you may want to enforce Multi-Factor Authentication (MFA) for users logging in from specific regions. First, you must have configured MFA in your Auth0 dashboard. This lets you define what additional factor you want to use. The next step is to force MFA when a user logs in from specific regions.
For example, assume you want to enforce MFA for North American users. You can create an Action with the following code:
exports.onExecutePostLogin = async (event, api) => { if (event.request.geoip.continentCode === "NA") { api.multifactor.enable("any"); }; };
In this case, you used the
continentCode
property of the geoip
object. If a user logs in to your application from one of the North American countries, you force MFA by invoking the api.multifactor.enable()
method. The "any"
string passed to the method tells Auth0 to use any of the configured factors. Alternatively, you can pass a string identifying a specific provider. Check out the documentation to learn the available values for MFA providers.To make your Action available to the Login Flow in your production environment, you have to click the Deploy button and drag the newly created Action into the Flow editor, as explained in the introduction to Auth0 Actions.
Recap
In conclusion, throughout this article, you learned the main reasons you may want to control user access to your application on a country-based criterion and how you can implement it with Auth0 Actions. You learned the geolocation features of the
event.request.geoip
object and how to leverage them to block users or enable MFA when they come from specific countries.However, remember that while the geolocation approach is pretty straightforward, it is not infallible.