Testing OpenID Connect jwt authentication of a .net core web application

dotnet
ios

#1

I am implementing OpenID Connect authentication for a mobile xamarin.ios app I am working on and the .net web service supporting it.

Environment:

  • xamarin.ios mobile app using xamarin’s version of the AppAuth.iOS component (works)
  • asp.net core mvc web application hosted in Azure as an App Service (works, authentication doesn’t work)

In my test I successfully log in using the mobile app through Okta’s federated web UI, with 2 factor authentication and receive populated AuthState which contains the id token, auth token, refresh token.

As a next step I am trying to test calling a simple endpoint on my web service using jwt authentication with the access token i received from the mobile app.

  • This endpoint works without any issues when not secured
  • I am trying to test the endpoint by calling it vial Postman by providing the Bearer Token Authorization type and populating the value with the access token received from the mobile app

Result: Bearer error=“invalid_token”, error_description=“The signature key was not found”

I setup the webservice following this Okta article:
https://developer.okta.com/quickstart/#/ios/dotnet/aspnetcore

In developer dashboard I don’t see any failures in the logs since it seems from the message that the token is failing to validate on the server side of my web service application.

Where else can i look to see why this token is failing to validate?
Am I providing the wrong token?

When I try to decode the token using https://jwt.io/ I get an error message that it has an invalid signature, not sure if that’s relevant or not.

Any help/suggestions at how I can debug this further and get it working would be greatly appreciated.

Dmitry

After inspecting the logs coming from my .net webservice during the token validation failure on requests to secured endpoints I see this error:

9m: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1]
      Failed to validate the token.
`Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match keys: 'WffpNetjfaITPwaP7gDQlK90pZC4xO47FDMa3FX1X10', 
token: '{"alg":"RS256","typ":"JWT","kid":"WffpNetjfaITPwaP7gDQlK90pZC4xO47FDMa3FX1X10"}.{"ver":1,"jti":"AT.7QYfubuKuh6ixclkCM06a3XIETR3QYw15uiQhzyqhJs.M0EqM7HebCP4RGdjR5mFTfmtkpSxX5ZLIvkB0oL+UIg=","iss":"https://xxxx.okta.com","aud":"https://xxxx.okta.com","sub":"dsamuylov@xxxx.com","iat":1527779914,"exp":1527783514,"cid":"0oa3xqtucfjboPdt91t7","uid":"00uu4f1rvlhuQwmGa1t6","scp":["offline_access","profile","openid"]}'.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Failed to validate the token.`

After further inspection of the opendid connect configuration settings from my account, i see that the kid of the key exposed through the keys endpoint doesn’t match the kid of the key used to sign the token i received after authenticating through the AppAuth component using the same okta account and application settings as I am using in the server application that is trying to validate the jwt token.

Either not all keys are exposed in the configuration or there’s some other reason for the keys are not matching up that I’m not seeing. Can anyone from the Okta technical team weigh in on what is happening here please?


#2

It looks like your issuer is the okta org’s authorization server. The access token that it generates is for Okta’s API and will not give you a key to validate it. This allows Okta to guarentee that our access_token isn’t used incorrectly for your apis.

Your application’s authorization server issuer url should resemble:

https://your-org-name.okta.com/oauth2/default 

From the issuer, you should be able to check your JWKS endpoint:

https://your-org-name.okta.com/oauth2/default/v1/keys

If I had to guess fast what will fix this, you need to configure the right issuer.

Let me know if this resolves the issue for you!


#3

Not 100% sure what you mean by Okta org’s authorization server.

I tested all this with a brand new developer account and the directions in this article:
https://developer.okta.com/quickstart/#/ios/dotnet/aspnetcore

The issuer for this test account is this:
https://dev-773947.oktapreview.com/oauth2/default

The openid-config url is this:
https://dev-773947.oktapreview.com/oauth2/default/.well-known/openid-configuration

The keys endpoint is this:
https://dev-773947.oktapreview.com/oauth2/default/v1/keys

The key it lists is UZk7W9TOmO2vbB8-j3-PHVHUsMx2gbfx-RuLDN8b8Es
The key the token is signed with is HD3v3KXvARUyg_9i26m2i8itsCY7TpA0-ajhcOsBdkM

My AppAuth settings in iOS client are:

    // The OIDC issuer from which the configuration will be discovered.
    public const string kIssuer = @"https://dev-773947.oktapreview.com"

    // The OAuth client ID.
    public const string kClientID = "0oafa27024puCyvwi0h7"

My Web-Service JWT config settings are:

services.AddJwtBearer(options => {
options.Authority = “https://dev-773947.oktapreview.com/oauth2/default”;
options.Audience = “0oafa27024puCyvwi0h7”;

            //options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
        });

Still getting the same error not being able to match keys.
I tried the issuer url format you suggested using our production account and I get a 404 error when I try to retrieve the .well-known/openid-configuration endpoint and if I use that url as my issuer i get an error message saying that it can’t retrieve the configuration.


#4
public const string kIssuer = @"https://dev-773947.oktapreview.com"

^ change that to:

public const string kIssuer = @"https://dev-773947.oktapreview.com/oauth2/default"

And you should be set.

To clear things up (haven’t had a coffee yet today):
The URL you are currently using is your the Okta API’s OAuth 2.0 issuer, it generates access_tokens for your Okta Org’s API. The access token can’t be used outside of Okta’s API’s (meaning it can’t be validated outside of Okta’s APIs).


#5

That solved the issue, the mismatch was the issuer url I was using in the iOS client. Thank you.

So this gets me half of the way there. I am now able to verify this setup working using a test developer account.

In our production account, if I go to the https://<<org-name>>.okta.com/oauth2/default/.well-known/openid-configuration

I get this error:

{
“errorCauses”: [

],
“errorCode”: “E0000015”,
“errorId”: “oaeCHddhZn6RaqXudJukqqLeA”,
“errorLink”: “E0000015”,
“errorSummary”: “You do not have permission to access the feature you are requesting”
}

Is there something that needs to be done to “give permission” to our org’s authorization server?


#6

Does that org have API Access Management?

One more question, if API Access Management is on the org, when was this org created? The default authorization server was something we added for convenience in 2017-08. If your org was created before then, you might need to reference it by ID:


#7

No, it doesn’t look like we have the “Authorization Servers” option under Security > API screen.

This account was created somewhere in the end of 2016 I believe.
How can we get the reference by ID to this authorization server for our account?


#8

Send an email to us at developers@okta.com

I believe either a) Your org doesn’t have the right flags or b) API Access Manager wasn’t purchased.

Thanks,
Tom


#9

So this basic functionality is exclusive to “API Access Manager” feature? I’m not interested in managing multiple APIs and multiple authorization servers, hence don’t need API Access Manager, I just need to access the default authorization server that all of the apps use that we create on our account.


#10

@tom thank you for your help so far

We purchased API Access Manager and so have access to our default authorization server

Workflow of what I’m trying to do:

  1. login into a mobile xamarin.ios app using AppAuth component configured to use openid-connect and Okta as the authorization server
  2. receive the access token from successful login and use it to call an asp.net core web-service which will use middleware to validate the jwt access token sent from the mobile client before returning the data back

Step 1. We setup a custom application in our Okta admin portal, here are the settings:


As you can see, the issuer on this application points to the root url for our organization which you pointed out to me earlier i believe points to the Okta API authorization server. This setup works on the mobile client to successfully login using our Active Directory logins and receive a jwt access token.

The problem is that this is a token being issued by the Okta API authorization server that I cannot validate inside my web-service which the mobile client needs to call after the user signs in. So there seems to still be a disconnect?

If I configure the mobile client’s AppAuth component’s issuer to be set to the default authorization server we received from signing up for API Access Manager, which looks like this .okta.com/oauth2/default, I get an error on the mobile client:
400 bad request
Identity Provider: Uknown
Error Code: invalid_client
Description: Invalid value for 'client_id' parameter

I have the clientid set in the AppAuth component to the value specified by the Mobile Test 2 application shown in the screenshots.

Do you see where my disconnect is? What am I missing?


#11

@dmitry Can you grab one of the access tokens obtained by the Xamarin client and paste it in to https://www.jsonwebtoken.io? What does the issuer and audience claim say?

Also, can you paste the configuration (Startup class) for your aspnetcore project?


#12

@nate.barbettini hey Nate, thank you for replying, I already figured this out, sorry for not updating this thread yet, here’s what happened:

@tom Thank you for being responsive, I actually figured out my issue. It was again a silly configuration mistake. I had the wrong clientid set after all, it was an artifact from the extensive testing I was doing for the previous problem and the clientid was set to one from a totally different account but it looked very close to the one that it needed to be set to that I didn’t notice right away. I did another round of double / triple checking all the settings and noticed the clientid was wrong. After updating to the correct one everything is working and the entire workflow I described is finally functioning. Thanks for your help!

@nate.barbettini thank you for the suggestion of inspecting the token contents for issuer and audience and clientid, great debugging tip, didn’t think of that earlier.


#13

Awesome, glad you got it working!