Search code examples
c#jwtgithub-api

C# GitHub Authentication Bad Request


I am trying to develop an authentication that can sync up two github repos using a GitHub App Authentication. I am using this documentation as reference. Below is the code that I have:

String PEMString = "xxxxx";
JsonWebTokenHandler JWTHandler = new JsonWebTokenHandler();
DateTime Now = DateTime.UtcNow;
PemReader Reader = new PemReader(new MemoryStream(Encoding.UTF8.GetBytes(PEMString)));
RsaSecurityKey RSAKey = new RsaSecurityKey(Reader.ReadRsaKey());
SigningCredentials Credentials = new SigningCredentials(RSAKey, SecurityAlgorithms.RsaSsaPssSha256);
JObject Payload = new JObject();
Payload.Add("iat", Now.TimeOfDay.Ticks);
Payload.Add("exp", Now.AddHours(1).TimeOfDay.Ticks);
Payload.Add("iss", <my app id>);
String JWTToken = JWTHandler.CreateToken(Payload.ToString(), Credentials);
HttpClient Client = new HttpClient();
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", JWTToken);
Client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json");
Client.GetAsync(new Uri("https://api.github.com/app/installations"));

When I execute it I got a 403 (Forbidden) error.
If I try to make a REST API call with Postman using the same JWTToken generated by the code, I got the following message:

{
    "message": "'Issued at' claim ('iat') must be an Integer representing the time that the assertion was issued",
    "documentation_url": "https://docs.github.com/rest"
}

The payload

enter image description here

As you can see both iat and exp are long, not int. How should I make the conversion to make it fit with an int?

Even when I am using "https://api.github.com/app/installations" as the url, this is just for making my code work with the documentation example, my final goal is to can use all the urls such as: https://api.github.com/repos/OWNER/REPO/contents/PATH


Solution

  • Using this code to calculate the iat and exp is wrong.

    Payload.Add("iat", Now.TimeOfDay.Ticks);
    Payload.Add("exp", Now.AddHours(1).TimeOfDay.Ticks);
    

    Ticks does not represent the UINX time, instead ticks are as defined here:

    The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 in the Gregorian calendar

    You need to use something like:

    long seconds = (long)DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds;
    

    See How to get the unix timestamp in C#