简体   繁体   中英

Keycloack for native /desktop application in c# REST APIs, not working properly or am I missing something?

I can get the authorization code and access token by a keycloak endpoint ONLY when I already have the browser opened and already did the login, otherwise the code fails to get the authorization code.

so considering I implement this logic at the application start ( it's not definitive ) , I have to run it 2 times to get code and then the token.

I just use rest APIs because I can not find an understandable keycloak library to use for desktop / native applications.

this is my code:

public static async  Task<string>  GetTokenAsync()
    {
 
        string redirectURI = string.Format("http://{0}:{1}/", "localhost", GetRandomUnusedPort());
        string RedirectURIWithoutLastSlash = redirectURI.TrimEnd('/');
 
 
        string code = await GetCodeForAuthentication(redirectURI, RedirectURIWithoutLastSlash);
 
        UnityWebRequest request = new UnityWebRequest();
        request.url = $"https://tokenEndpoint.../protocol/openid-connect/token";
 
        request.method = UnityWebRequest.kHttpVerbPOST;
        request.downloadHandler = new DownloadHandlerBuffer();
       
 
 
        request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 
        string postData = "";
 
        Dictionary<string, string> postParameters = new Dictionary<string, string>() /
            {
                {"grant_type", "authorization_code"},
                {"code", code},
                {"client_id", "myID"},
                {"client_secret", "mySECRET"},
                {"redirect_uri", RedirectURIWithoutLastSlash }
            };
 
        foreach (string key in postParameters.Keys)
            postData += UnityWebRequest.EscapeURL(key) + "=" + UnityWebRequest.EscapeURL(postParameters[key]) + "&";
 
        byte[] data = Encoding.ASCII.GetBytes(postData);
 
        request.uploadHandler = new UploadHandlerRaw(data) ;
 
        request.timeout = 60;
 
        request.SendWebRequest();
 
        while (!request.isDone)
        {
            Debug.Log(request.downloadProgress);
        }
 
        Debug.Log("text by server is: " + request.downloadHandler.text);
 
        TokenClass token = JsonUtility.FromJson<TokenClass>(request.downloadHandler.text);
 
        access_token = token.access_token;
 
        tokenInfo = token;
        Debug.Log("access token is: " + access_token);
 
        return access_token;
    }
 
    private static async Task<string> GetCodeForAuthentication(string redirectURI, string RedirectURIWithoutLastSlash)
    {
 
     
 
        string code = null;
 
        HttpListener http = new HttpListener();
        http.Prefixes.Add(redirectURI);
        http.Start();
 
 
 
        string authorizationRequest = $"https://authCode Endpoint.../protocol/openid-connect/auth?client_id=myID&response_type=code&response_mode=query&scope=profile&redirect_uri={RedirectURIWithoutLastSlash}";
 
        // Opens request in the browser.
        Process web_Login_Process = new Process();
        web_Login_Process.StartInfo.FileName = GetSystemDefaultBrowser();
        web_Login_Process.StartInfo.Arguments = authorizationRequest;
        web_Login_Process.Start();
 
 
            try
            {
             
                var context = await http.GetContextAsync();
                var response = context.Response;
 
                var html = "<html><head><meta http-equiv='refresh' content='10;url=https://localhost'></head><body>Please return to the Digital Twin.</body></html>";
 
 
                string responseString = string.Format(html);
                var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
                response.ContentLength64 = buffer.Length;
                var responseOutput = response.OutputStream;
                Task responseTask = responseOutput.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
                {
                    responseOutput.Close();
                    http.Stop();
                    Console.WriteLine("HTTP server stopped.");
                });
           
           
            // Checks for errors.
            if (context.Request.QueryString.Get("error") != null)
                {
                    string debug = context.Request.QueryString.Get("error");
 
                }
                if (context.Request.QueryString.Get("code") == null
                    || context.Request.QueryString.Get("state") == null)
                {
 
                    var debug = context.Request.QueryString; //no keys, Lenght is equal to 0
 
                    var debug3 = context.Request.RawUrl; // favicon.ico is the result
 
 
                }
                // extracts the code
                code = context.Request.QueryString.Get("code");
 
                string tryCode = context.Request.QueryString["code"];
 
                Debug.Log("code is: " + code);
 
               
 
            }
            catch (Exception ex)
            {
                string g = ex.Message;
            }
 
        return code;
    }

any help on this would be really appreciated.

There is a C# Sample that you can follow for the desktop flow and borrow some ideas from. Note that the OAuth flow for console apps is the same as for desktop apps.

You should be using PKCE for the desktop app security and the above library will implement this for you

For something to compare against with the correct OAuth behaviour, see these resources of mine:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM