Ensuring that the correct people have the approved access when they need it can be difficult when you are coding your application.
In this workshop we will walk you through how you can grant access to specific resources by defining runtime actions and assigning role-based permissions to your users using App ID. You will also learn how the sample application validates users' scopes to provide a different experience according to their role.
Before you can start creating roles and scopes, you need to be sure that you have the following prerequisites:
- An instance of App ID: We will see it through IBM Cloud
- An application: I will provide sample app to you.
- App users. For this Tutorial, we will creat the users Bob, Peter, and Ted in Cloud Directory.
1.1- If you are an existing user please this link to Login: https://ibm.biz/appsecurity
And if you are not, don't worry! We have got you covered! There are 3 steps to create your account on IBM Cloud:
1.2- Put your email and password.
1.3- You get a verification link with the registered email to verify your account.
1.4- Fill the personal information fields.
** Please make sure you select the country you are in when asked at any step of the registration process.
2.1- In the search bar type "App ID", click the instance from search result, it will take you to a new window. Click create botton to start your App ID instance
2.2- Click create botton to start your App ID instance
3.1 - Download the sample app From workshop's Git Repository click on code and download zip file. Unzip the file to a path of your choice.
You can also use this link to Download the sample app.
4.1 - Add localhost:3000/* to your list of allowed redirect URIs. You can edit your allowed redirect URIs by going to Manage Authentication > Authentication Settings, http://localhost:3000/
5.1 - From App ID Dashboard, select Applications in the left pane, click on add a new application.
5.2 - Give your application a unique name and define the scopes elevator.call, elevator.stop, and elevator.service to represent the specific operations that the different roles can perform. click on save.
6.1 - Go to Cloud Directory > Users, Click on create users
6.2 - Add your user details and click save
7.1. Now that App ID is configured, scopes are created and we have the users that we need, let's walk through creating roles. Create your roles by going to Roles and profiles > Roles > Create role.
For our workshop we will create roles Caller and Technician.
Give name caller and add scope "Elevator/elevator.call"
Give name Technician and add scopes "Elevator/elevator.call", "Elevator/elevator.stop", "Elevator/elevator.service"
8.1 - Assign the roles to specific application users by going to Roles and profiles > User profiles. Then, choose the user that you want to assign the role to and select from available roles to assign
Note: I used the credentials of my elevator application in the configuration of my sample applications in localdev-config.json. To grab your credentials, open your application in the Applications page of the App ID dashboard.
After creating the roles and assigning them to users, I want my application to verify the users' scopes when performing certain operations. To do this, I will define some endpoints on my application that will either use App ID's WebApp Strategy or send a request to backend endpoints that I will also define, which will perform the validation by using App ID's API Strategy.
Using the elevator app as an example, you can see how I secure the following endpoint by using the hasScope method in WebAppStrategy to check whether the access token contains the elevator.service and elevator.stop scopes:
// This endpoint will return true if we should show the technician menu.
// we show this menu if request's access token contains the scopes "elevator.stop" and "elevator.service".
app.get("/protected/api/shouldShowTechnicianMenu", (req, res) => {
res.send(WebAppStrategy.hasScope(req, 'elevator.service elevator.stop')); });
These three endpoints call backend server endpoints to validate that the access token contains the elevator.call, elevator.service, and elevator.stop scopes respectively:
// Call protected endpoint on backend, where we will check if the access token has the "elevator.call" scope.
app.get("/protected/callElevator", async function(req, res) {
const options = {
url: 'http://localhost:1234/protected/callElevator',
headers: {
'Authorization': 'Bearer ' + req.session[WebAppStrategy.AUTH_CONTEXT].accessToken
}
};
try {
await request(options);
res.send('The elevator will arrive shortly.');
}catch(e) {
res.send("You don't have permissions to perform this action.");
}
});
// Call protected endpoint on backend, where we will check if the access token has the "elevator.service" scope.
app.get("/protected/serviceMode", async function(req, res) {
const options = {
url: 'http://localhost:1234/protected/serviceMode',
headers: {
'Authorization': 'Bearer ' + req.session[WebAppStrategy.AUTH_CONTEXT].accessToken
}
};
try {
await request(options);
res.send("Elevator is on service mode.");
}catch(e) {
res.send("You don't have permissions to perform this action.");
}
});
// Call protected endpoint on backend, where we will check if the access token has the "elevator.stop" scope.
app.get("/protected/stopElevator", async function(req, res) {
const options = {
url: 'http://localhost:1234/protected/stopElevator',
headers: {
'Authorization': 'Bearer ' + req.session[WebAppStrategy.AUTH_CONTEXT].accessToken
}
};
try{
await request(options);
res.send("Elevator is now stopped.");
} catch (e) {
res.send("You don't have permissions to perform this action.");
}
});
These endpoints on the backend server use APIStrategy to validate that the access token contains the elevator.call, elevator.service, and elevator.stop scopes respectively:
app.get("/protected/callElevator",
passport.authenticate(APIStrategy.STRATEGY_NAME, {
audience: config.clientId,
scope: "elevator.call",
session: false
}),
function(req, res) {
res.send('success');
});
app.get("/protected/serviceMode",
passport.authenticate(APIStrategy.STRATEGY_NAME, {
audience: config.clientId,
scope: "elevator.service",
session: false
}),
function(req, res) {
res.send('success');
});
app.get("/protected/stopElevator",
passport.authenticate(APIStrategy.STRATEGY_NAME, {
audience: config.clientId,
scope: "elevator.stop",
session: false
}),
function(req, res) {
res.send('success');
});
You need to build and run both "Elevators-backend" and "Elevators-app" for your app to run successfully.
npm install npm start
In this workshop, we showed you how to use App ID to manage users access permissions to your application's resources. Hopefully, now you feel confident in your ability to set up your App ID instance with scopes and roles and set up your application to manage access according to the roles that you assigned.
Login/Sign Up for IBM Cloud: https://ibm.biz/appsecurity
Workshop Replay: https://www.crowdcast.io/e/journey-to-low-code-no-code-app-security-3
configure social identity providers to set up a single sign-on experience for your app : https://cloud.ibm.com/docs/appid?topic=appid-social&interface=ui
Securely Manage access to your Applications Sensitive Data on IBM Cloud https://www.crowdcast.io/e/journey-to-low-code-no-code-app-security-1
Easily Secure your Spring boot app with Low code/No Code https://www.crowdcast.io/e/journey-to-low-code-no-code-app-security-2