So, after eventually falling blank with the documentations on getting the Socialite configs working with Microsoft Entra ( specifically the role mappings ). I had to patch the Socialite code to get it to work. The way Libre Maps scopes etc and groups is a bit backwards. But to get this to work. Set up per the documentations with Librenms.
lnms plugin:add socialiteproviders/microsoft
lnms config:set auth.socialite.configs.microsoft.client_id ds22389d-cea2-4a78-ab19-ee11213e90b1725
lnms config:set auth.socialite.configs.microsoft.client_secret 71148Q~L0Z21313eph0nS2kc7231sddddd2PmlaM9
lnms config:set auth.socialite.configs.microsoft.tenant 912sds56-8223-481112-8658e-4115166eb5
lnms config:set auth.socialite.configs.microsoft.listener “\SocialiteProviders\Microsoft\MicrosoftExtendSocialite”
lnms config:set auth.socialite.default_role global-read
lnms config:set auth.socialite.claims.sdf3c8a-9c2a-43sd-92c1-43fsdcc515d.roles ‘[“admin”]’
lnms config:set auth.socialite.scopes.0 “openid”
lnms config:set auth.socialite.scopes.1 “profile”
lnms config:set auth.socialite.scopes.2 “email”
lnms config:set auth.socialite.scopes.3 “https://graph.microsoft.com/User.Read”
lnms config:set auth.socialite.scopes.4 “https://graph.microsoft.com/Group.Read.All”
[ This is example data]
Make sure your user is part of the group you are using for the claims.
Now on your group claims:
click the hotdog, and edit:
you need to emit the claims as roles:
You now need to patch the Socialite Controller to actually read these.
/opt/librenms/app/Http/Controllers/Auth/SocialiteController.php
Look for the function setRolesFromClaim and add as per the comments below:
private function setRolesFromClaim(string $provider, $user): bool
{
$scopes = LibrenmsConfig::get('auth.socialite.scopes');
$claims = LibrenmsConfig::get('auth.socialite.claims');
if (is_array($scopes) &&
$this->socialite_user instanceof \Laravel\Socialite\AbstractUser &&
! empty($claims)
) {
$roles = [];
$attributes = $this->socialite_user->getRaw();
if (is_object(current($attributes)) && method_exists(current($attributes), 'getName') && method_exists(current($attributes), 'getAllAttributeValues')) {
$parsed_attributes = [];
foreach ($attributes as $attribute_object) {
$attribute_name = $attribute_object->getName();
$attribute_values = $attribute_object->getAllAttributeValues();
$parsed_attributes[$attribute_name] = $attribute_values;
}
$attributes = $parsed_attributes;
}
// CHECK FOR 'roles' ATTRIBUTE EXPLICITLY (for Microsoft groups emitted as roles)
if (isset($attributes['roles']) && is_array($attributes['roles'])) {
foreach ($attributes['roles'] as $group_id) {
$roles = array_merge($roles, $claims[$group_id]['roles'] ?? []);
}
}
// ORIGINAL LOGIC - check scope matching
foreach ($scopes as $scope) {
foreach ($attributes as $attribute_name => $attribute_values) {
if (str_contains($attribute_name, $scope)) {
foreach (Arr::wrap($attributes[$attribute_name] ?? []) as $scope_data) {
$roles = array_merge($roles, $claims[$scope_data]['roles'] ?? []);
}
}
}
}
if (count($roles) > 0) {
$user->syncRoles(array_unique($roles));
return true;
}
}
return false;
}
Hope this helps others that have been trying to get this working.

