public string ConstructRedirectUrl(DiscourseSsoReturnPayload payload) { string signature; string discoursePayloadUrlEncoded = CreateSsoPayload(payload, out signature); if (DiscourseServerUrl.EndsWith("/")) { DiscourseServerUrl = DiscourseServerUrl.Substring(0, DiscourseServerUrl.Length - 1); } //Don't use AddQueryParam as sso payload is already URL encoded and that will invalidate signature. return(DiscourseServerUrl + "/session/sso_login?sso=" + discoursePayloadUrlEncoded + "&sig=" + signature); }
private string CreateSsoPayload(DiscourseSsoReturnPayload payload, out string signature) { var discoursePayloadRawString = "nonce={0}&name={1}&username={2}&email={3}&external_id={4}".Fmt( payload.Nonce, payload.Name, payload.UserName, payload.Email, payload.ExternalId); var discoursePayloadBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(discoursePayloadRawString)); var discoursePayloadUrlEncoded = discoursePayloadBase64.UrlEncode(); var sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(DiscourseSsoSecret)); //signature needs to be generated off the base64 payload, NOT the url ended base64 payload... //https://meta.discourse.org/t/official-single-sign-on-for-discourse/13045/71 signature = HashEncode(sha256.ComputeHash(Encoding.UTF8.GetBytes(discoursePayloadBase64))); return(discoursePayloadUrlEncoded); }