I am currently using the following PHP code in Laravel to authenticate and obtain an embed URL for Power BI reports. However, I would like to enhance the security of my Azure AD app by replacing the current client secret-based authentication with a self-signed certificate.
Here is my current code which is working with client secret.
<?php
namespace App\Http\Controllers;
use App\Models\MenuTool;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class PowerBIController extends ApiController
{
private function getAccessToken()
{
$response = Http::asForm()->post("https://login.microsoftonline.com/" . env('PBI_TENANT_ID') . "/oauth2/v2.0/token", [
'grant_type' => env('PBI_GRANT_TYPE'),
'client_id' => env('PBI_CLIENT_ID'),
'client_secret' => env('PBI_CLIENT_SECRET'),
'scope' => env('PBI_SCOPE'),
])->body();
return $response;
}
private function generatePowerBIToken($group_id, $report_id)
{
$token = json_decode($this->getAccessToken())->access_token;
$token_response = Http::asForm()
->withHeaders([
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer ' . $token,
])
->post("https://api.powerbi.com/v1.0/myorg/groups/" . $group_id . "/reports/" . $report_id . "/GenerateToken", [
'grant_type' => env('PBI_GRANT_TYPE'),
]);
$embed_response = $this->getEmbedUrl($token, $group_id, $report_id);
return ["token" => $token_response->json()['token'], "report_id" => $embed_response['id'], 'embed_url' => $embed_response['embedUrl']];
}
private function getEmbedUrl($token, $group_id, $report_id)
{
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $token,
])
->get("https://api.powerbi.com/v1.0/myorg/groups/$group_id/reports/$report_id");
return $response->json();
}
public function index($lang, $slug)
{
try {
$menu = MenuTool::where('slug', $slug)->where('lang', $lang)->first();
if ($menu) {
if (auth()->user()->isClient()) {
$product_ids = array_column(auth()->user()->client->products->toArray(), "id");
if (in_array($menu->product_id, $product_ids)) {
$token = $this->generatePowerBIToken($menu->group_id, $menu->report_id);
return $this->successResponse($token);
}
return $this->errorResponse("Forbidden", 403);
} else {
$token = $this->generatePowerBIToken($menu->group_id, $menu->report_id);
return $this->successResponse($token);
}
}
return $this->errorResponse("Report not found", 404);
} catch (\Throwable $th) {
return $this->errorResponse($th->getMessage(), 500);
}
}
}
I have already created a self-signed certificate and uploaded it to my Azure AD app. Now, I am struggling with the integration of the certificate-based authentication into the existing code.
Could someone please provide guidance or a code snippet on how to modify the existing code to use the self-signed certificate for authentication instead of the client secret? Any additional steps or considerations for working with certificates in this context would be greatly appreciated.
Thank you in advance!
In my case, I followed this MS Document and created client assertion successfully like this:
Response:
When I used this assertion in below parameters, I got the access token successfully via Postman:
Response:
Using this token, I'm able to call Power BI API and retrieved report details like this:
Response:
In your case, create client assertion similarly and generate access token by modifying below part in your code:
Reference:
OAuth 2.0 client credentials flow on the Microsoft identity platform