Skip to content

Instantly share code, notes, and snippets.

@cajuncoding
Created May 22, 2023 04:52
Show Gist options
  • Save cajuncoding/5d716d0ad1b55e35e70759fb4df0d3e7 to your computer and use it in GitHub Desktop.
Save cajuncoding/5d716d0ad1b55e35e70759fb4df0d3e7 to your computer and use it in GitHub Desktop.
Simple PKCE Generator for Code Verifier & Code Challenge tokens in C# (to be used in the Auth Code Authentication Flow with Azure AD, etc.)
using System;
using System.Security.Cryptography;
using System.Text;
namespace CajunCoding.PKCE
{
/// <summary>
/// BBernard / CajunCoding
/// A simple class to generate Proof Key for Code Exchange (PKCE) codes to be used in the Authorization code authentication flow.
///
/// It is dependent on the TokenIdGenerator (Gist is here: https://gist.github.com/cajuncoding/9d11518e388082e0520676012bb94f5e)
/// to Generates a highly unique code verifier that is an alpha-numerically complex value of arbitrary length (default is the
/// max recommended 128 characters), as well as the corresponding SHA256 hash of the verifier as a one-way hash;
/// of which the original code verifier value cannot be guessed from the derived hash value.
///
/// NOTE: Code Verifier values should be alphanumerically complex values with length of at least 43 characters but no more than 128.
/// </summary>
public class PKCEGenerator
{
public static PKCECodes NewCodes(int verifierCodeLength = 128)
{
var codeVerifier = TokenIdGenerator.NewTokenId(verifierCodeLength);
var codeChallenge = CreateCodeChallenge(codeVerifier);
return new PKCECodes(codeVerifier, codeChallenge);
}
public static string CreateCodeChallenge(string codeVerifier)
{
using var sha256 = SHA256.Create();
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
var base64Challenge = Convert.ToBase64String(challengeBytes);
//Now the Base64 value must be sanitized with URL safe encoding; as required by Auth code flow implementations (e.g Azure AD) to use it for validation.
var codeChallenge = base64Challenge
.TrimEnd('=') //Sanitize the value
.Replace('+', '-') //Map invalid '+' Url char
.Replace('/', '_'); //Map invalid '/' Url char
return codeChallenge;
}
}
/// <summary>
/// BBernard / CajunCoding
/// A set of corresponding PKCE Codes generated by teh PKCEGenerator.
/// </summary>
public class PKCECodes
{
public PKCECodes(string codeVerifier, string codeChallenge)
{
CodeVerifier = codeVerifier;
CodeChallenge = codeChallenge;
}
/// <summary>
/// The original code used as the verifier of a challenge that is derived from this code via SHA256 Hash.
/// </summary>
public string CodeVerifier { get; }
/// <summary>
/// The SHA256 Hash of teh CodeVerifier; to be used as the Code Challenge in the Auth Code authentication flow.
/// </summary>
public string CodeChallenge { get; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment