Validating the id_token when using OAuth2

Hello

I'm trying to change our azure app to use the new oauth2 authentication against SuperOffice Online. I have managed to get to the step where I need to validate the returned id_token. Since we are running our app in Azure, the SuperOfficeFederatedLogin.crt file is put on disk and loaded before validating the token. Here is the code I'm using:

var tokenHandler = new SuperIdTokenHandler();

// Load the correct cerfiticate from disk
tokenHandler.JwtIssuerSigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(HttpContext.Current.Server.MapPath("~/App_Data/sod/") + "SuperOfficeFederatedLogin.crt");

// Validate my token
var superIdClaims = tokenHandler.ValidateToken(id_token, SuperOffice.SuperID.Contracts.SystemUser.V1.TokenType.Jwt);

The code above fails with the following error: 

IDX10205: Issuer validation failed. Issuer: 'https://sod.superoffice.com'. Did not match: validationParameters.ValidIssuer: 'SuperOffice AS' or validationParameters.ValidIssuers: 'null'

The error is quite easy to solve. All I need to do is to add this line of code before I call ValidateToken(...) method:

tokenHandler.ValidIssuer = "https://sod.superoffice.com";

My question is, why do I have to add this ValidIssuer line? Am I using an old certificate or am I using a bad "code-practice"? 

Thank you



RE: Validating the id_token when using OAuth2

The reason for the valid-issuer problem is that we don't have the private key for the certificate, so we can't validate that the issuer of the certificate is correct.

Here is a snippet from a sample app that needs to go up on GitHub soon:

        [Route("api/callback")]
        [HttpGet]
        public HttpResponseMessage CallbackAccessToken([FromUri]string code)
        {
            string url = ConfigurationManager.AppSettings["SuperIdUrl"];
            var query = Request.GetQueryNameValuePairs();

            var form = new Dictionary<string, string>();
            form["code"] = code;
            form["client_id"] = ConfigurationManager.AppSettings["AppId"];
            form["client_secret"] = ConfigurationManager.AppSettings["AppSecret"];
            form["grant_type"] = "authorization_code";
            form["redirect_uri"] = ConfigurationManager.AppSettings["RedirectUrl"];
            var body = new FormUrlEncodedContent(form);

// uses flurl to get JWT from SuperId
            dynamic response = url
                .AppendPathSegment("common/oauth/tokens")
                .WithHeader("Accept", "application/json")
                .PostAsync(body)
                .ReceiveJson().Result;

            string jwt = response.id_token;

// use System.IdentityModel.Tokens.Jwt and Microsoft.IdentityModel.Tokens
            SecurityToken validatedToken = null;
            TokenValidationParameters validationParameters = new TokenValidationParameters();
            validationParameters.IssuerSigningKey = Certificate.DefaultX509Key_Public_2048;
            validationParameters.ValidateAudience = false;
            validationParameters.ValidateIssuer = false; // We don't have private key 

            var handler = new JwtSecurityTokenHandler();
            handler.ValidateToken(jwt, validationParameters, out validatedToken);

            if (validatedToken != null)
            {
                string access_token = response.access_token;
                string refresh_token = response.refresh_token;
                var jwToken = validatedToken as JwtSecurityToken;
                var custCtx = jwToken.Claims.FirstOrDefault( c => c.Type == "http://schemes.superoffice.net/identity/ctx" );
                var cust = custCtx?.Value;
                var apiurlCtx = jwToken.Claims.FirstOrDefault(c => c.Type == "http://schemes.superoffice.net/identity/webapi_url");
                var apiurl = apiurlCtx?.Value;
            }
By: Christian Mogensen 22 Feb 2019

RE: Validating the id_token when using OAuth2

Hello 

Public certificate is used for validating a signature, not the private one. Private one is used for generating the signature. 

 

There are two different types of JWT tokens in Online. One is the "good" old with issuer SuperOffice AS and it is incompatible with OpenId Connect (OIDC). If your application receives a form value with the name jwt, this is usually this one. SuperIdTokenHandler can validate this type of token correctly. 

The other one, "id_token" defined in OpenId Connect, has other claims and validation rules and has an environment specific issuer (https://sod.superoffice.com in sod, https://online.superoffice.com in prod). SuperIdTokenHandler does not comply with the requirements of id_token. The signature and issuer will be validated, but claims such as at_hash or nonce will not. 

I do believe using well known libraries for OIDC is the way to go. If you for instance are writing an ASP.NET Core application, you can easily add Online as an OIDC Identity Provider and get the neccesarry tokens (including validation).

We have adopted the discovery standard (https://sod.superoffice.com/login/.well-known/openid-configuration) which includes information about the endpoints and signing keys. No need to store the certificate along with your application. (And it will allow us to roll certificates when needed without thinking about breaking all of your applications). 

Tony has made available a couple of examples on Github: https://github.com/SuperOffice/DevNet-Angular-OpenID-REST and https://github.com/SuperOffice/SuperOffice.DevNet.OpenIDConnectNativeApp

 

--

HansO

[removed bottom empty lines]

By: Hans Oluf Waaler 22 Feb 2019

RE: Validating the id_token when using OAuth2

You should update these docs as presented code doesn't work without this ValidIssuer-fix (at least when testing with SOD):

https://community.superoffice.com/en/developer/create-apps/how-to/develop/override-certificate-resolver/

By: Mikko Tillikainen 14 May 2020

RE: Validating the id_token when using OAuth2

Hi Mikko,

Could you be a little more specific. What doesn't work for you vs. what does.

Best regards.

By: Tony Yates 14 May 2020

RE: Validating the id_token when using OAuth2

Well I had to use same fix as Arild in first post. So this kind of code worked with SOD:

public static SuperIdToken ValidateToken(string token)
{
  var tokenHandler = new SuperIdTokenHandler();

  tokenHandler.JwtIssuerSigningCertificate = new X509Certificate2("Certificates\\SuperOfficeDevelopment.crt");
  tokenHandler.ValidIssuer = "https://sod.superoffice.com";
  tokenHandler.CertificateValidator = X509CertificateValidator.None;
  return tokenHandler.ValidateToken(token, TokenType.Jwt);
}

Compared to what is in link:

https://community.superoffice.com/en/developer/create-apps/how-to/develop/override-certificate-resolver/

Not a big thing itself, but it's very confusing if "official" example code throws cryptic exceptions.

By: Mikko Tillikainen 15 May 2020

RE: Validating the id_token when using OAuth2

Ah, right! Of course. Thank you for pointing out the article's shortcoming. I have updated the article to include the ValidIssue. 

Thank you for pointing this out to us!

Best regards.

By: Tony Yates 15 May 2020