Created
August 27, 2023 18:20
-
-
Save msfayed/10a7ad2f16a76d29eb09ccd48aa7ea1d to your computer and use it in GitHub Desktop.
LIQPad oauth2-oidc-client to test https://github.com/msfayed/oauth2-oidc-mock or any OICD server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Program | |
| { | |
| static async Task Main(string[] args) | |
| { | |
| var _usePKCE = false; | |
| // ====================================== | |
| var clientId = "clientId"; | |
| var clientSecret = "clientSecret"; | |
| //_usePKCE = true; // for SPA/Mobile (without backend) | |
| // ====================================== | |
| var authorizationEndpoint = "http://localhost:8090/authorize"; | |
| var tokenEndpoint = "http://localhost:8090/token"; | |
| var redirectUri = "http://localhost:8080/"; | |
| var scope = "openid profile email"; // Adjust the scope based on your needs | |
| var state = Guid.NewGuid().ToString(); | |
| var authorizeUrl = $"{authorizationEndpoint}?client_id={clientId}&redirect_uri={HttpUtility.UrlEncode(redirectUri)}&response_type=code&scope={System.Web.HttpUtility.UrlEncode(scope)}&state={state}"; | |
| var code_verifier = ""; | |
| var code_challenge = ""; | |
| if (_usePKCE) | |
| { | |
| code_verifier = getCodeVerifier(); | |
| code_challenge = getCodeChallenge(code_verifier); | |
| authorizeUrl += $"&code_challenge={code_challenge}&code_challenge_method=S256 "; | |
| } | |
| Clipboard.SetText(authorizeUrl); | |
| Console.WriteLine("Please open the following URL in your browser to authenticate: [ already in your clipboard ;) ] \n\n"); | |
| Console.WriteLine(authorizeUrl + "\n\n"); | |
| using (var listener = new HttpListener()) | |
| { | |
| listener.Prefixes.Add(redirectUri); | |
| listener.Start(); | |
| Console.WriteLine("Waiting for callback..."); | |
| while (true) | |
| { | |
| var context = await listener.GetContextAsync(); | |
| var request = context.Request; | |
| if (request.HttpMethod == "GET") | |
| { | |
| var queryParameters = HttpUtility.ParseQueryString(request.Url.Query); | |
| var authorizationCode = queryParameters["code"]; | |
| var receivedState = queryParameters["state"]; | |
| var tokenContent = ""; | |
| if (receivedState == state) | |
| { | |
| // Exchange authorization code for access token | |
| Console.WriteLine($"Received authorization code: {authorizationCode}\n\n"); | |
| var tokenClient = new System.Net.Http.HttpClient(); | |
| var tokenRequest = new Dictionary<string, string> | |
| { | |
| { "grant_type", "authorization_code" }, | |
| { "code", authorizationCode }, | |
| { "redirect_uri", redirectUri }, | |
| { "client_id", clientId } | |
| }; | |
| if (_usePKCE) | |
| { | |
| tokenRequest.Add("code_verifier", code_verifier); | |
| } | |
| else | |
| { | |
| tokenRequest.Add("client_secret", clientSecret); | |
| } | |
| var tokenResponse = await tokenClient.PostAsync(tokenEndpoint, new FormUrlEncodedContent(tokenRequest)); | |
| tokenContent = await tokenResponse.Content.ReadAsStringAsync(); | |
| Console.WriteLine($"Token Response: {tokenContent}"); | |
| } | |
| else | |
| { | |
| Console.WriteLine("Received state does not match."); | |
| } | |
| string responseString = "Authorization successful.\nJWT can be decoded at: https://jwt.io/ \nResponse:\n\n" + tokenContent; | |
| byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString); | |
| context.Response.AddHeader("Content-Type", "application/json; charset=utf-8"); | |
| context.Response.ContentLength64 = buffer.Length; | |
| context.Response.OutputStream.Write(buffer, 0, buffer.Length); | |
| context.Response.Close(); | |
| break; | |
| } | |
| } | |
| listener.Stop(); | |
| } | |
| } | |
| static string getCodeVerifier() | |
| { | |
| var rng = RandomNumberGenerator.Create(); | |
| var bytes = new byte[32]; | |
| rng.GetBytes(bytes); | |
| // It is recommended to use a URL-safe string as code_verifier. | |
| // See section 4 of RFC 7636 for more details. | |
| return Convert.ToBase64String(bytes) | |
| .TrimEnd('=') | |
| .Replace('+', '-') | |
| .Replace('/', '_'); | |
| } | |
| static string getCodeChallenge(string val) | |
| { | |
| using (var sha256 = SHA256.Create()) | |
| { | |
| var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(val)); | |
| return Convert.ToBase64String(challengeBytes) | |
| .TrimEnd('=') | |
| .Replace('+', '-') | |
| .Replace('/', '_'); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment