- 18 Oct 2024
- 6 Minutes à lire
- SombreLumière
Shielding the Application via the Shielding API
- Mis à jour le 18 Oct 2024
- 6 Minutes à lire
- SombreLumière
App Shielding and the OneSpan Mobile Portal also allow you to shield your apps via the App Shielding API.
Initial setup
The steps described below need to be performed for the initial setup only.
App Shielding API—initial setup
To set up the App Shielding API
Generate the client ID and client secret from the App Shielding user interface on the OneSpan Mobile Portal.
You only need to generate these once as they apply to all your projects, except if either of the two is compromised. In that case, you must generate a new ID or secret.
Generate the configuration key from the App Shielding user interface on the OneSpan Mobile Portal.
Generate a separate key for each project as well as for each App Shielding version!
Copy the client ID, client secret, and configuration key from the App Shielding user interface and set it in your automation script(s), CI/CD pipeline etc.
Shielding apps
Once you have set up the App Shielding API, you can shield your apps with it.
Sample scripts
OneSpan provides sample scripts for shielding an app with the App Shielding API. You can use the scripts provided in shieldingapps.zip to start shielding the app, obtain the shielding progress, and download the shielded app.
These scripts are only examples to demonstrate how to shield an app with the public APIs!
Workflows to shield apps
The steps described below are performed every time you shield your app(s) with the API.
App Shielding API—shielding flow
To shield apps with the API
Obtain the access token via the authentication server with the client ID and client secret you created during initial setup with the POST /oauth2/token authorization endpoint.
Endpoint signature:
Header: Authorization: BasicYOUR_CLIENT_CREDENTIALS
Header: Content-Type: application/x-www-form-urlencoded
Request body: grant_type=client_credentials
Response body sample (JSON):
{ "access_token": "AUTHORIZATION_TOKEN", "expires_in": 3600, "token_type": "Bearer" }
where access_token is the authorization token which must be added to the header when invoking all shielding REST APIs.
Status response: 200
Implement the following in your pipeline:
client_id = <CLIENT_ID> # Replace with your Client ID obtained/copied during initial setup. client_secret = <CLIENT_SECRET> # Replace with your Client Secret obtained/copied during initial setup. auth_server_url = "https://auth.mobile.onespan.com/oauth2/token" # The Auth server URL payload = 'grant_type=client_credentials' headers = {'Content-Type': 'application/x-www-form-urlencoded'} response = requests.request("POST", auth_server_url, headers=headers, data=payload, auth=HTTPBasicAuth(client_id, client_secret)) # client_id and client_secret obtained during initial setup. access_token = response.json().get('access_token') # JWT token used in REST API requests for authorization
Obtain the upload URL for uploading the mobile app to the storage server via the REST API with the POST /v1/shieldingapps public shielding endpoint. This creates a signed upload URL to upload the mobile app to be shielded.
Endpoint signature:
Host: https://api-appshielding.mobile.onespan.com/v1/shieldingapps
Header: Authorization: BearerAUTHORIZATION_TOKEN
Request body sample (JSON):
{ "configurationKey": "0ef41a59-1eb9-1234-abcd-7368f5149a8b", "shielderPlatform": "ANDROID", "fileNameWithExt": "some_android_mobile.apk" }
where:
configurationKey is the key obtained from the user interface
shielderPlatform is the mobile platform, with two possible values, ANDROID or IOS)
fileNameWithExt is the full file name with file extension of the app to be uploaded.
Status response: 200
Response body sample (JSON):
{ "url": "https://<long-pre-signed-url>/<to-upload>", "expiredAt": "2024-06-19T17:09:16.995169312Z", "uuid": "512729d2-dbf0-9876-dcba-491c441a1122" }
where:
url is the pre-signed URL to use for uploading the mobile app to the storage server.
uuid is the unique identifier used to map the individual mobile app shielding process. You will need this uuid to check the shielding progress or to download the shielded mobile app via the shielding REST APIs.
Implement the following in your pipeline:
base_shieldingapps_api_url = "https://api-radium.mobile.eu.onespan.com/v1/shieldingapps" # The API service URL configuration_key_value = <CONFIGURATION_KEY> # Replace with your Configuration Key obtained/copied during initial setup. shielder_platform_value = <PLATFORM> # Replace with the corresponding platform: ANDROID or IOS file_name_with_ext_value = <APP_FILE_NAME> # Replace with your mobile application file name and extension e.g: app.apk app.ipa headers = { 'Content-Type': 'application/json', 'Authorization': f"Bearer {access_token}" # Access token obtained via the authentication server with the Client ID and Client Secret. } payload = json.dumps({ "configurationKey": configuration_key_value, "shielderPlatform": shielder_platform_value, "fileNameWithExt": file_name_with_ext_value }) response = requests.request("POST", base_shieldingapps_api_url, headers=headers, data=payload) if response.status_code == 201: print(f"Upload URL successfully created") pre_signed_url = response.json().get('url') # The URL for uploading the mobile app to be shielded. shielding_uuid = response.json().get('uuid') # The UUID reference to the shielding process. else: print("Something went wrong when trying to obtained Upload URL!!") print(response.text)
Upload the mobile app to the storage server with the pre-signed upload URL from the public shielding endpoint.
Upload request signature:
PUT https//long-pre-signed-url/to-upload
data: file_content
Status response: 200
Implement the following in your pipeline:
file_path = <PATH_FILE_NAME> #Replace with the path to your local file e.g: /home/apps/app.apk try: with open(file_path, 'rb') as file: payload_file_content = file.read() except FileNotFoundError: print(f"File not found: {file_path}") exit(1) headers = {'Content-Type': 'application/octet-stream'} response = requests.request("PUT", pre_signed_url, headers=headers, data=payload_file_content) response.raise_for_status() print("File uploaded successfully!!")
Once the app is completely uploaded to the storage server, invoke the Start Shielding REST API with POST /v1/shieldingapps?uuid=SHIELDING-UUID. This starts the shielding process of a mobile app previously uploaded, using the SHIELDING_UUID value obtained with the upload URL.
Endpoint signature:
Host: https://api-appshielding.mobile.onespan.com/v1/shieldingapps
Query parameter required: uuid=SHIELDING_UUID
Header: Authorization: BearerAUTHORIZATION_TOKEN
Provide your value attributes: Request body sample (JSON).
{ "configurationKey": "0ef41a59-1eb9-1234-abcd-7368f5149a8b", "fileNameWithExt": "some_android_mobile.apk" }
where:
configurationKey is the key obtained from the user interface
fileNameWithExt is the full file name with file extension of the app to be uploaded.
Status response: 201
Response body sample (JSON):
{ "uuid": "512729d2-dbf0-9876-dcba-491c441a1122" }
where uuid is the same as that provided as query parameter.
Implement the following in your pipeline:
start_shieldingapps_api_url = f"{base_shieldingapps_api_url}?uuid={shielding_uuid}" # Same shielding_uuid obtained with the upload URL. payload = json.dumps({ "configurationKey": configuration_key_value, # Your Configuration Key obtained during initial setup. "fileNameWithExt": file_name_with_ext_value # Same as provided with the upload URL. }) headers = { 'Content-Type': 'application/json', 'Authorization': f"Bearer {access_token}" # Access token obtained via the authentication server with the Client ID and Client Secret. } response = requests.request("POST", start_shieldingapps_api_url, headers=headers, data=payload) if response.status_code == 201: print(f"App Shielding successfully started : {response.json().get('uuid')}") else: print("Something went wrong when trying to start App shielding!!")
After the shielding process has started, your pipeline can query the API at regular intervals to monitor the shielding progress with the Shielding Progress REST API. Get log details of the shielding process with GET /v1/shieldingapps?uuid=512729d2-dbf0-9876-dcba-491c441a1122&action=progress, using the SHIELDING_UUID value obtained with the upload URL.
The Get Shielding Progress REST API can be invoked multiple times to obtain the progress, until the shielding status changes to FAILED or SUCCESS.
Endpoint signature:
Host: https://api-appshielding.mobile.onespan.com/v1/shieldingapps
Query parameter required: uuid=SHIELDING_UUID, action=progress
Header: Authorization: BearerAUTHORIZATION_TOKEN
Response body sample (JSON):
In progress:
{ "uuid": "512729d2-dbf0-9876-dcba-491c441a1122", "shieldingStatus": "IN_PROGRESS", "progressInPercent": 14, "progressTimestamp": "2024-06-27T17:51:39.432Z", "shieldingLogs": "Cleaning workspace...\nLoading data...\nWriting temporary configuration files...\nRunning Shielder...\n* Shielding app: /tmp/...\nShielder for Android, version 6.5.3 (id: OneSpan, Jigsaw: 1.15.0)\n* Decoding application\n..." }
where:
shieldingStatus is the status of the shielding process. When it is in progress, log details are available.
shieldingLogs are the log details of the shielding process.
progressInPercent is the progress in percent of the shielding process.
Status response: 200
Completed:
{ "uuid": "512729d2-dbf0-9876-dcba-491c441a1122", "shieldingStatus": "SUCCESS" }
where shieldingStatus is the status of the shielding process. When it is in progress, log details are available.
Implement the following in your pipeline:
progress_shieldingapps_api_url = f"{base_shieldingapps_api_url}?uuid={shielding_uuid}&action=progress" # Same shielding_uuid obtained with the Upload URL. headers = {'Authorization': f"Bearer {access_token}"} # Access token obtained during initial setup. response_progress = requests.request("GET", progress_shieldingapps_api_url, headers=headers) if response_progress.status_code == 200: print(f"Response: {response_progress.json()}") # Shielding progress details else: print("Something went wrong when trying to get App shielding progress!!")
Once shielding has completed, obtain the download URL via the REST API with GET /v1/shieldingapps?uuid=512729d2-dbf0-9876-dcba-491c441a1122&action=download, using the SHIELDING_UUID value obtained with the upload URL.
Endpoint signature:
Host: https://api-appshielding.mobile.onespan.com/v1/shieldingapps
Query parameter required: uuid=SHIELDING_UUID, action=download
Header: Authorization: BearerAUTHORIZATION_TOKEN
Response body sample (JSON):
{ "url": "https://long-pre-signed-url/to-download", "expiredAt": "2024-06-19T18:10:16.995169312Z", }
url is the pre-signed URL to use for downloading the mobile app from the storage server
Status response: 200
Implement the following in your pipeline:
download_shieldingapps_api_url = f"{base_shieldingapps_api_url}?uuid={shielding_uuid}&action=download" headers = {'Authorization': f"Bearer {access_token}"} response_download = requests.request("GET", download_shieldingapps_api_url, headers=headers) if response_download.status_code == 200: print(f"Response download: {response_download.json()}") response_download_url = response_download.json().get('url') print(f"Shielded App Download URL: {response_download_url}") else: print("Something went wrong when trying to get App shielding download URL!!")
(Optional) Download the shielded mobile app via your pipeline from the storage server with the pre-signed URL obtained in the previous step. The shielded app and other files will be downloaded as a .zip file.
Download request signature:
URL: DOWNLOAD_URL obtained from the public shielding endpoint.
GET https//long-pre-signed-url/to-download
Status response: 200
Implement the following in your pipeline:
shielded_app_download_url = response_download_url # Same URL obtained as Upload URL. response_shielded_download = requests.request("GET", shielded_app_download_url) if response_shielded_download.status_code == 200: print(f"File successfully downloaded") shielded_filename = os.path.basename(urlparse(response_shielded_download.url).path) output_shielded_file = os.path.join(shielded_filename) # Stored locally. Update it to your output path print(f"Filename: {shielded_filename}") with open(output_shielded_file, "wb") as file: file.write(response_shielded_download.content) print(f"File successfully stored") else: print("Something went wrong when trying to download the shielded App!!")