Keycloak in C# WPF Application: How can I access the roles of a given user/password in C# in a normal MVVM WPF application?

Viewed 1259

I am looking for a working implementation of a Keycloak Client in C#. Both projects on github from DylanPlecki and MattMorg (later) did not work for me and are most probably not longer maintained.

My task is to get all roles of a given user to implement a more refined db access on our data base server. So actually I am keycloak not as an Authentication server in the first place, but more to get information of the user. In our company we are in the beginning of consequently using OAUTh2.0 ;-).

So here is my question: Does anyone know, how to access a keycloak server most efficiently to protect the security of the app and get the roles? Maybe via RestAPI somehow, or OIDC Protocol?

1 Answers

@Thomas Brüggemann's answer brought me (in the end) on the right path :

I used The RestClient class to get the roles of my user. Finally unresolved is that I have to store the typed in credentials in RAM. That is for sure better solved in the keycloak login page implementation, if you are in the context of a webapp. But I go on looking for a better solution. Perhaps as a first step, I will delete the user/password combination directly after getting the tokens.

My aim was to access a keycloak server to get the roles which I need to refine my user management. As a very raw test example, I get a dictionary in the last line, containing all roles of the requested user:

using RestSharp;
using System.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.Security.Claims;
using System.Web;
using System.Security.Principal;
using Microsoft.AspNet.Identity;
[..]

    
[..]
    public String GetAccessAndRefreshToken()
    {
        RestClient client = new RestClient("http://YourKeycloakServer:YourKCPort/auth/realms/YourRealm/protocol/openid-connect/token");

        RestRequest request = new RestRequest(Method.POST);
        request.AddHeader("cache-control", "no-cache");
        request.AddHeader("content-type", "application/x-www-form-urlencoded");
        request.AddParameter("grant_type", "password");
        request.AddParameter("client_id", "YourAppsNameInKeycloak");
        request.AddParameter("username", AuthenticationViewModel.UserName);
        request.AddParameter("password", AuthenticationViewModel.Pass);
        request.AddParameter("client_secret", "YourSecretinKeycloak");
        IRestResponse response = client.Execute(request);
        String content = response.Content;
        return content;
    }

    public List<String> GetRoles(String content)
    {
        JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();
        //string pattern = @"{\n.* ""(.*)"",";
        String pattern = @".*access_token\"":\""(.*)\"",\""expires.*";
        MatchCollection accessTokenMatch = Regex.Matches(content, pattern, RegexOptions.IgnoreCase);
        var group1 = (String)accessTokenMatch[0].Groups[1].ToString();
        JwtSecurityToken token = (JwtSecurityToken)jwtHandler.ReadToken((String)accessTokenMatch[0].Groups[1].ToString());

        Claim realmAccessClaim = token.Claims.First((claim) => claim.Type == "realm_access");
        Dictionary<string, string[]> realmAccessAsDict = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(realmAccessClaim.Value);
        List<String> roles = realmAccessAsDict.FirstOrDefault().Value.ToList();
        return roles;
    }
[..]

In the end you get a list of roles as a string and you are able to manually parse them.

Related