DEV Community

Cover image for Build your own OAuth 2.0 Server and OpenId Connect Provider in ASP.NET Core 6.0

Build your own OAuth 2.0 Server and OpenId Connect Provider in ASP.NET Core 6.0

Mohammed Ahmed Hussien on October 28, 2022

Update 20, April 2023 This article is out of date because I added more functionality to this OAuth server, so to be more updated I suggest download...
Collapse
 
svetelak profile image
Svetelak

Hi, could I ask for some advice? I'm starting with OAuth and I downloaded your server project and I'm trying to connect a test (client) application to it. After starting the OAuth server and the Client, the login screen appears correctly if I am not logged in. After logging in, it redirects to the url where I have the client application (sample: https://localhost:7285/signin-oidc?response_type=code&state=CfDJ8Ecxanf86J1JnZZYH7c8PDzfq9Skgyu5iPZeW31rddOYS-I9c2n8jR...), but this error SecurityTokenException: Unable to validate is displayed the 'id_token', no suitable ISecurityTokenValidator was found for: ''.".
If I edit the url (localhost:7285/), the application is logged in.
I couldn't get to the root cause. Can I ask you for some advice?
Thank you very much Lubos

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien • Edited

Hi, sure, can you show me the configuration that you have been make at the client level.

Be sure to remove these lines of codes from the client application.

options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = false,
                SignatureValidator = delegate(string token, TokenValidationParameters validationParameters)
                {
                    var jwt = new JwtSecurityToken(token);
                    return jwt;
                },
            };
Enter fullscreen mode Exit fullscreen mode

Because the source code in the GitHub repo now is support the key validator

Collapse
 
svetelak profile image
Svetelak

Hi, thank you very much for your response. I am sending a link to the entire project, where I try and test it
dcfreenet.info/0_test/TestOpenAuth...
My goal will be client applications in Bl@zor
And thank you for adding to your answer. I will try what you wrote.

Collapse
 
svetelak profile image
Svetelak

Hi, I already tried to remove options.TokenValidationParameters from the client according to your advice... but the result is still the same. Both in the Bl@zor project and in the MVC project. I'm sending a command.

Image description

Collapse
 
svetelak profile image
Svetelak

So I tried to remove the given code but the result was the same :-(

Thread Thread
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Let me check your source code

Thread Thread
 
svetelak profile image
Svetelak

Thanks for the reply, so I'm sending the link to github.
github.com/Svetelak/OAuthServerTes...

Thread Thread
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Sorry for late to response, yeah there is a bug, the bug is that the user is not logged-in and in the GenerateToken method like so

  if (!clientCodeChecker.Subject.Identity.IsAuthenticated)
                    // I have to inform the caller to redirect the user to the login page
                    return new TokenResponse { Error = ErrorTypeEnum.InvalidGrant.GetEnumDescription() };
Enter fullscreen mode Exit fullscreen mode

I will fix that this weekend.

Thread Thread
 
svetelak profile image
Svetelak

Super thank you very much. As soon as it's ok, I'll test :-)
Thank you so much

Thread Thread
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Hi, the bug is fixed, you can try now from your side.
I try it with Balzor app it's working.
this is the fixed commit:
github.com/Shoogn/OAuth20Server/co...

Thread Thread
 
svetelak profile image
Svetelak

I tried it and it works! Thank you very much, perfect job

Collapse
 
mperudirectio profile image
mperudirectio • Edited

Hello, just following the first steps of the tutorial.
when i start the two applications the ~/.well-known/openid-configuration endpoint it's not fired. Could it be because I'm working on an api project and not mvc? thanks!

This is the starup config of the client (registered in my oauth server project)

builder.Services.AddAuthentication(config =>
{
    config.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    config.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,  options =>
{
    // OAuth Server Port
    options.Authority = "https://localhost:7039";

    options.ClientId = "directiofadlrs";
    options.ClientSecret = "123456789";
    options.ResponseType = "code";
    options.CallbackPath = "/signin-oidc";
    options.SaveTokens = true;

    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = false,
        SignatureValidator = (string token, TokenValidationParameters _) => new JwtSecurityToken(token),
    };
});
Enter fullscreen mode Exit fullscreen mode

SOLVED
I forgot to decorate the Client controller with the [Authorize] attribute!

Collapse
 
tamasvarga1988 profile image
Tamás Varga

Hi, I tried to change the RSA xml to a new one generated by:

using var rsa = new RSACryptoServiceProvider(2048);
var xml = rsa.ToXmlString(true);
Enter fullscreen mode Exit fullscreen mode

When I try to login with my client I get "Signature validation failed. Token does not have a kid. Keys tried: 'System.Text.StringBuilder'".

Should I change anything else, or the generated key is wrong? The original works fine.

Collapse
 
tamasvarga1988 profile image
Tamás Varga

Found it. I had to replace "n" and "kid" values in jwks.json under wwwroot folder to the Modulus of the new RSA XML.

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Glad to here that, and if you want to change the entire directory, you can navigate to the DiscoveryEndpointController object there is an Action Method named Jwk you will find the current patch assigned to wwwroot folder from there you can provide your preferred path

Collapse
 
programatix profile image
Nicholas Poh • Edited

I'm testing out your Authorization Server from github and I can successfully login through it, which either resulted in creating a new account or log in to at my side. However when I tried to link exiting account on my side to your Authorization Server (via myserver/Identity/Account/Manage/E...), I'm getting the following exception on the Authorization Server,

System.Security.Cryptography.CryptographicException: 'The payload was invalid. For more information go to aka.ms/dataprotectionwarning'

If I ignore the exception, the Authorization Server's login page will be shown and upon entering the credential, the exception occurs again. On my side, the debug log shows,

Request starting HTTP/2 GET https://localhost:44329/signin-oidc?response_type=code&state=CfD...
AuthenticationScheme: Identity.External signed in.
Request finished HTTP/2 GET https://localhost:44329/signin-oidc?response_type=code&state=CfD... - - - 302 0 - 44.9488ms
Request starting HTTP/2 GET localhost:44329/Identity/Account/M... - -
Exception thrown: 'System.Security.Cryptography.CryptographicException' in Microsoft.AspNetCore.DataProtection.dll
Identity.Application was not authenticated. Failure message: Unprotect ticket failed

Any advice?

Collapse
 
programatix profile image
Nicholas Poh

Issue resolved. We cannot use the same hostname for both the client and the server even when the ports are different. I tried with different hostnames and it works.

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien • Edited

I'm very glad you know about this point, and you fix the problem

Collapse
 
faisallibra profile image
Faisal Shahzad • Edited

Thanks for the post. I'm need to have the similar solution and I'm using your example in our case. I have created two different domains client and server on the windows server 2019. Test is successfully authenticating the request but while calling back the following URL getting error page. Anyone can help?

Image description

Following is the callback URL

https://<client domain>/signin-oidc?response_type=code&state=CfDJ8ECkv9oAtGxNm2CqZXor7SUGMwvQj3_9ANUG193arlR7-OOacaFoYMP50c6IdSD7YdSfHHQgOIeLbrBDuDgdW60l1Lm8Ulcu6w6nI0_QOcqi-OR_v-wCXFw44RUJG0xibVecc06tB2QXQjlrACUd8aGG61eQJCs0GBnAItLP4Zn06tMb1M1n3jPXXagHh2QX7Bic2M4BgFqkRcoWxOyfDX2-9Lhht4MxIi-xRZ3w8dDUy0F2QiNvz-bakvWd3vfjEge66sUWXG-T-MkS8zep7ralR3rUstMqoxwgz7NOvJGbkkpi6fYL5F0amhYdstrC4_4npohGgEzUiKSxqsAPi6Key0D9uKOQnDl7tpHoLRPG5AXBsDdID11QUGVqIZPVmQ&code=fsYat7bISln_lWnKYxrP-4gAHcxs7U_9tq1fArrIWLA

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Hi, you can not call this url direc because the auth server generate the code foe one time and also the client generate the state for one time as well.

Collapse
 
naseer profile image
Naseer Ahmad • Edited

Hi,
Many thanks for sharing your application. I have executed both (client & server) applications successfully but when I deployed on the server. it shown shared error while return from server. Please help me, I am struck.

Please response urgently
Image description

Collapse
 
naseer profile image
Naseer Ahmad

@mohammedahmed Please guide about it

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Can you share the Auth Server App and Client app through github link

Collapse
 
mnarsidani profile image
Moez

Hello Sir, what an amazinf post and interesting contribution. Thanks for that. is it possible if you can update this article to align with latest github code. so, a beginner would have more in-depth understanding about all componennts and will have easy to implement code.

Collapse
 
kdudley21 profile image
kdudley21

Would then allow me to use SSO with the Authorization Server ? Where If I Log In With ClientID 2 I can then go to the homecontroller for lets say ClientID 3 and it will know I already logged in with ClientID 2 ?

Collapse
 
antonio_faletar_9304e34a5 profile image
Antonio Faletar

@mohammedahmed , I see that you are using a local SQL server database. You didn't provide the db, right?

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Yeah, you can run the migration script
Update-Database

Collapse
 
melbaay profile image
Melchor

How to change InMemory to a database the OAuthOption

Collapse
 
daconsulting profile image
DAConsulting

I am also curious about this. Where can one find this script? Did not come down with the git clone...

Collapse
 
kdudley21 profile image
kdudley21

Where is the Update-Database migration script located ?

Collapse
 
jcestrella profile image
Juan Carlos Estrella

How can I implement the cliente credentials flow?

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

It's very easy, all you have to do is to call the token endpoint directly.

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Hey, now it's implemented, give it a try!

Collapse
 
jcestrella profile image
Juan Carlos Estrella

Oh, nice, thanks

Collapse
 
ahmedanwar100 profile image
Ahmed Anwar

When we will get the next post

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Stay tuned!

Collapse
 
mimz profile image
mo

please provide link to next post

Collapse
 
melbaay profile image
Melchor

Hi got this error message after login: SecurityTokenInvalidIssuerException: IDX10211: Unable to validate issuer. The 'issuer' parameter is null or whitespace

Collapse
 
leedonhyun profile image
leedonhyun

builder.Services.Configure(configServices.GetSection("OAuthOptions"));
-->
builder.Services.Configure(configServices.GetSection("OAuthOption"));

Collapse
 
hebatps profile image
hebatps

i have same error, any update ?

Collapse
 
mimz profile image
mo

You have mentioned: "Ooooooops we do it, now we need to improve our Authorization Server code and application structure. This is the next step. see you in the next post."

Where is the next post?

Collapse
 
melbaay profile image
Melchor

How to change InMemory Client Store to dynamic

Collapse
 
ashongwe profile image
Andile Shongwe

Hi

After receiving the access token I get the folowing error. Could you please assist?
DataError: The JWK "alg" member was inconsistent with that specified by the Web Crypto call.

Collapse
 
kubop profile image
Jakub Pernica

Do I understand it correctly that this doesn't implement generating the refresh_token and retrieving it? Are you planning on implementing it?

Collapse
 
mohammedahmed profile image
Mohammed Ahmed Hussien

Hi, yeah there no refresh_token support at this time, but Im going to put it in my plan next month

Collapse
 
ibanafa profile image
iBanafa

i guess we're in business

Collapse
 
bilal_ko_464f39f6531d2cc profile image
Bilal Koç

It's very nice. Congratulations. Nothing is missing.Could you add receiving protected data when you make a request with an access token to your project?

Collapse
 
zndgocu profile image
soure_repository • Edited

Hi, dear,
could i get the client app?