I’m returning to eve after a long pause and all my own tools are not working anymore so I thought I jump onto the swagger train as it’s a nice challenge.
I have gotten my authentication to work with the code challenge and all the jazz and I also successfully get the token and I can verify and grab the data in that token with no issue. Now I am trying to call my first ESI call. I’ve created implementations for a status call and a character skills call just to make sure I can do unauthorized calls to the ESI and authorized calls.
Server status call works great, so my implementation works fine on unauthorized calls, but when I try to authorized calls I get the same response no matter what I do:
My authorization grants to all scopes and I can see in the token that it has the ‘esi-skills.read_skills.v1’ required for character skills. As far as I understand the Authorization token is just the access token you get when to complete the code challenge right? At least that is what I get from the ESI documentation: Sending an authenticated request to ESI | esi-docs
does your JWT validate correctly against EVE’s public RSA key listed in the jwks?
there are a lot of libs around that lets you do it, or you can verify it online with https://jwt.io if you revoke your token after writing it there / ready to accept the risk of a token leak
Thank you @BusError. I have forgotten that I have removed that step during some testing and never get around to it. Been trying to do it for a while now, but I am apparently not particularly strong in security algorithms. I fail to understand the link between the jwks information and how to use it to do the validation.
FYI, building a WCF .net core application, so if anyone has a good example of this, I would jump for joy.
With a lot of profanities and tea, I got the Validation part working. Reading this readme and reading the rfc7517 specifications got me on the right track. Of cause, it was very easy when I had all the parts. The problem on the ESI endpoint where Authentication is required is still an issue even with a validated token. I am right to assume that the validation is just to confirm the token is valid and does not change the token in any way?
I posted my validation code here if that helps:
Summary
public void ValidateCurrentToken(AccessInfo info)
{
var eveJwksJson = GetEveTokenSecurityKeyInfo();
var tokenHandler = new JwtSecurityTokenHandler();
var keyset = JsonWebKeySet.Create(eveJwksJson);
var tokenParameters = new TokenValidationParameters();
tokenParameters.ValidateIssuerSigningKey = true;
tokenParameters.ValidateIssuer = true;
tokenParameters.ValidateAudience = false;
tokenParameters.ValidateLifetime = true;
tokenParameters.ValidateActor = false;
tokenParameters.ValidIssuers = new List<string>{ "https://login.eveonline.com", "login.eveonline.com" };
tokenParameters.IssuerSigningKey = keyset.Keys.First();
SecurityToken validatedToken;
try
{
tokenHandler.ValidateToken(info.AccessToken, tokenParameters, out validatedToken);
}
catch(Exception e)
{
throw new AuthenticationException("Token is not valid: " + e.Message);
}
var securityToken = (JwtSecurityToken) validatedToken;
info.CharacterId = Convert.ToInt32(securityToken.Subject.Replace("CHARACTER:EVE:", ""));
info.Issued = securityToken.IssuedAt;
info.ValidTo = securityToken.ValidTo;
info.Scopes.AddRange(securityToken.Claims.Where(claim => claim.Type == "scp").Select(claim => claim.Value));
AccessInfo = info;
SaveAccessInfo();
}
Yeah, it’s just for you — to make sure the token is valid. It does not affect the token itself. The only thing I notices, if you do not process token by a validation liibrary, you need to convert info.AccessToken to an object manually because it’s presented as a Base64 string. Validating libraries usually convert it under the hood, and you have a converted payload after using them.
So the access token mentioned in the ESI documentation about sending Esi Authenticated requests is not the value you get from the SSO, and I need to convert that JWT token into something else?
Ah .NET. Last I worked with it WIF was the way to do federated identity and Visual studio can just be pointed to a jwks url and it would generate most of the configs for you.
Umm, it’s the same JWT, but it’s just not converted from Base64-encoded string to a plain object. As I remember, when I was implementing and debugging SSO on my website, manually decoded Base64 string and the same string processed with a validation library produced the same payload in result.
I’m beginning to wonder if I have missed something basic in the way I need to call the ESI. I failed multiple attempts on getting my code to work, so now I have tested it on Fiddler. If I can get it to work there, I can get it to work anywhere. But I can’t! it won’t work! If I sound frustrated at this point, that is because I am.
I can call /status/ end point without an issue:
GET https://esi.evetech.net/latest/status/ HTTP/1.1
Host: esi.evetech.net
HTTP/1.1 200 OK
Date: Fri, 15 Oct 2021 17:52:31 GMT
<other headers omitted>
{"players":24526,"server_version":"1952234","start_time":"2021-10-15T11:04:47Z"}
So no problem contacting esi. Then I try to get my characters skills, but without authorization:
GET https://esi.evetech.net/latest/characters/726604936/skills/ HTTP/1.1
Host: esi.evetech.net
HTTP/1.1 401 Unauthorized
Date: Fri, 15 Oct 2021 17:31:41 GMT
<headers omitted>
{"error":"authorization not provided"}
This response makes perfect sense, as I haven’t added the token yet. So I authorize and get a fresh token to use, and add it to the request:
I am out of ideas at this point. THIS… should have worked. I have done EXACTLY as the documentation says or as any other forums or sources indicate. I have checked my client credentials and permissions and they are all set up to call this endpoint. My token is validated and has all the information that the ESI documentation says it has.
GET https://esi.evetech.net/latest/characters/726604936/skills/ HTTP/1.1
Host: esi.evetech.net
Authorization: Bearer <omitted>
HTTP/1.1 200 OK
Date: Fri, 15 Oct 2021 18:55:13 GMT
<header omitted>
{"skills":[{"active_skill <cutoff>
The worst part is that I remembered that I thought I should just try one, but then my lazy brain went “naa, just pick everything!”. Thank you SO MUCH for that!