C
C#2mo ago
K1lleR99

If I handled the SSO oauth as client in the backend [ASP.NET] how to integrate it with the frontend?

I'm not familiar with OpenIdConnect/OAuth and I had to integrate my project with my organization's SSO In the backend (ASP.NET) I did it and handled the callback and everything and made it as an OAuth client and it is that what gets the access token and everything now the frontend (Angular) is another service with another domain how to make the angular app to read the authentication if the user is authenticated or his authentication is expired or not and what's his role and claims and so on and the right way to do it
so I don't want to generate now client id and client secret for the Angular App service but I want it the same as the backend one and to be integrated together and once it done from the backend should be passed to the frontend in short how to pass the authentication from the backend (which is just a client) to the frontend app so I don't want to generate now client id and client secret for the Angular App service but I want it the same as the backend one and to be integrated together and once it done from the backend should be passed to the frontend I need the backend to handle the SSO authentication integration like getting the token and user info and registering it in the database if a first time or some actions and just passing it to the frontend but I need the right way to do, like if the SSO token is expired or something the Angular App must be aligned up with that also what is that cookie called Identity.External that I see after the sso login and how it works the asp.net app still shows me that the request is not authenticated even within it it comes here to this selected commented code after the sso is logged successfully so it is supposed to be work
No description
18 Replies
K1lleR99
K1lleR992mo ago
code:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
//options.LoginPath = "/account/clogin";
}) // For session-based authentication
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// Set the identity provider's base URL (this will handle discovery of other endpoints)
options.Authority = authOptions.Authority;
options.MetadataAddress = authOptions.MetadataAddress;

// Client ID and Client Secret for your application
options.ClientId = authOptions.ClientId;
options.ClientSecret = authOptions.ClientSecret;

// Specify the type of OpenID Connect flow (Authorization Code flow in this case)
options.ResponseType = OpenIdConnectResponseType.Code;

// Save tokens (access_token, id_token) in the authentication ticket
options.SaveTokens = true;

// Handle the callback after login
options.CallbackPath = authOptions.CallbackPath;
//options.CallbackPath = "/api/odc/callback";

//options.ForwardSignIn

// Fetch user info after authentication
options.GetClaimsFromUserInfoEndpoint = true;
//options.ForwardSignIn = CookieAuthenticationDefaults.AuthenticationScheme;

// Scope includes 'openid' which is required for OpenID Connect
options.Scope.Add("openid");

//options.Scope.Add("openid");
//options.Scope.Add("profile");
//options.Scope.Add("email");

options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.HttpContext.Response.Headers.Add("OIDC-DEBUG", "Redirecting to IDP"); // Add custom headers for debugging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 500;
context.HandleResponse();
return context.Response.WriteAsync("Authentication failed: " + context.Exception.Message);
},
OnAccessDenied = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 403;
context.HandleResponse();
return context.Response.WriteAsync("Access denied: " + context.Result.ToString());
},
//OnAuthorizationCodeReceived = context =>
//{
// // Capture and log more detailed error messages
// context.Response.StatusCode = 200;
// context.HandleResponse();
// return context.Response.WriteAsync("Authorization code received: " + context.TokenEndpointRequest.Code);
//},

OnRemoteFailure = context =>
{
// Capture remote failures for better error handling
context.HandleResponse();

context.Response.Redirect("/error?message=" + context.Failure?.Message);
return Task.CompletedTask;
}
};


// JWT Signing algorithm based on metadata
//options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
//{
// ValidIssuer = authOptions.Authority,
// NameClaimType = "email",
// RoleClaimType = "role"
//};
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
//options.LoginPath = "/account/clogin";
}) // For session-based authentication
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// Set the identity provider's base URL (this will handle discovery of other endpoints)
options.Authority = authOptions.Authority;
options.MetadataAddress = authOptions.MetadataAddress;

// Client ID and Client Secret for your application
options.ClientId = authOptions.ClientId;
options.ClientSecret = authOptions.ClientSecret;

// Specify the type of OpenID Connect flow (Authorization Code flow in this case)
options.ResponseType = OpenIdConnectResponseType.Code;

// Save tokens (access_token, id_token) in the authentication ticket
options.SaveTokens = true;

// Handle the callback after login
options.CallbackPath = authOptions.CallbackPath;
//options.CallbackPath = "/api/odc/callback";

//options.ForwardSignIn

// Fetch user info after authentication
options.GetClaimsFromUserInfoEndpoint = true;
//options.ForwardSignIn = CookieAuthenticationDefaults.AuthenticationScheme;

// Scope includes 'openid' which is required for OpenID Connect
options.Scope.Add("openid");

//options.Scope.Add("openid");
//options.Scope.Add("profile");
//options.Scope.Add("email");

options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.HttpContext.Response.Headers.Add("OIDC-DEBUG", "Redirecting to IDP"); // Add custom headers for debugging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 500;
context.HandleResponse();
return context.Response.WriteAsync("Authentication failed: " + context.Exception.Message);
},
OnAccessDenied = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 403;
context.HandleResponse();
return context.Response.WriteAsync("Access denied: " + context.Result.ToString());
},
//OnAuthorizationCodeReceived = context =>
//{
// // Capture and log more detailed error messages
// context.Response.StatusCode = 200;
// context.HandleResponse();
// return context.Response.WriteAsync("Authorization code received: " + context.TokenEndpointRequest.Code);
//},

OnRemoteFailure = context =>
{
// Capture remote failures for better error handling
context.HandleResponse();

context.Response.Redirect("/error?message=" + context.Failure?.Message);
return Task.CompletedTask;
}
};


// JWT Signing algorithm based on metadata
//options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
//{
// ValidIssuer = authOptions.Authority,
// NameClaimType = "email",
// RoleClaimType = "role"
//};
});
Sossenbinder
Sossenbinder2mo ago
There are multiple conceptual ways to solve it. Most important question - Is this backend a general purpose one, or is it dedicated to this specific frontend app? Also does it have to be on a different domain?
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX2mo ago
If you have no further questions, please use /close to mark the forum thread as answered
K1lleR99
K1lleR992mo ago
there is admin frontend app and normal client frontend app connected to the backend app service they r diff sub domains could be anything I have no idea about the correct way yet I see Identity.External in the cookies about no idea what it does or how to handle
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
K1lleR99
K1lleR992mo ago
what is the bff 😅
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
K1lleR99
K1lleR992mo ago
backend for frontend gotcha
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
K1lleR99
K1lleR992mo ago
in some extensions cs file:
var authOptions = services.BindValidateReturn<OpenIdOptions>(config);
services.AddOptions<JwtSettings>()
.BindConfiguration(nameof(JwtSettings))
.ValidateDataAnnotations()
.ValidateOnStart();

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
//options.LoginPath = "/account/clogin";
}) // For session-based authentication
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// Set the identity provider's base URL (this will handle discovery of other endpoints)
options.Authority = authOptions.Authority;
options.MetadataAddress = authOptions.MetadataAddress;

// Client ID and Client Secret for your application
options.ClientId = authOptions.ClientId;
options.ClientSecret = authOptions.ClientSecret;

// Specify the type of OpenID Connect flow (Authorization Code flow in this case)
options.ResponseType = OpenIdConnectResponseType.Code;

// Save tokens (access_token, id_token) in the authentication ticket
options.SaveTokens = true;

// Handle the callback after login
options.CallbackPath = authOptions.CallbackPath;
//options.CallbackPath = "/api/odc/callback";

//options.ForwardSignIn

// Fetch user info after authentication
options.GetClaimsFromUserInfoEndpoint = true;
//options.ForwardSignIn = CookieAuthenticationDefaults.AuthenticationScheme;

// Scope includes 'openid' which is required for OpenID Connect
options.Scope.Add("openid");

//options.Scope.Add("openid");
//options.Scope.Add("profile");
//options.Scope.Add("email");

options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.HttpContext.Response.Headers.Add("OIDC-DEBUG", "Redirecting to IDP"); // Add custom headers for debugging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 500;
context.HandleResponse();
return context.Response.WriteAsync("Authentication failed: " + context.Exception.Message);
},
OnAccessDenied = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 403;
context.HandleResponse();
return context.Response.WriteAsync("Access denied: " + context.Result.ToString());
},
//OnAuthorizationCodeReceived = context =>
//{
// // Capture and log more detailed error messages
// context.Response.StatusCode = 200;
// context.HandleResponse();
// return context.Response.WriteAsync("Authorization code received: " + context.TokenEndpointRequest.Code);
//},

OnRemoteFailure = context =>
{
// Capture remote failures for better error handling
context.HandleResponse();

context.Response.Redirect("/error?message=" + context.Failure?.Message);
return Task.CompletedTask;
}
};


// JWT Signing algorithm based on metadata
//options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
//{
// ValidIssuer = authOptions.Authority,
// NameClaimType = "email",
// RoleClaimType = "role"
//};
});
var authOptions = services.BindValidateReturn<OpenIdOptions>(config);
services.AddOptions<JwtSettings>()
.BindConfiguration(nameof(JwtSettings))
.ValidateDataAnnotations()
.ValidateOnStart();

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
//options.LoginPath = "/account/clogin";
}) // For session-based authentication
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// Set the identity provider's base URL (this will handle discovery of other endpoints)
options.Authority = authOptions.Authority;
options.MetadataAddress = authOptions.MetadataAddress;

// Client ID and Client Secret for your application
options.ClientId = authOptions.ClientId;
options.ClientSecret = authOptions.ClientSecret;

// Specify the type of OpenID Connect flow (Authorization Code flow in this case)
options.ResponseType = OpenIdConnectResponseType.Code;

// Save tokens (access_token, id_token) in the authentication ticket
options.SaveTokens = true;

// Handle the callback after login
options.CallbackPath = authOptions.CallbackPath;
//options.CallbackPath = "/api/odc/callback";

//options.ForwardSignIn

// Fetch user info after authentication
options.GetClaimsFromUserInfoEndpoint = true;
//options.ForwardSignIn = CookieAuthenticationDefaults.AuthenticationScheme;

// Scope includes 'openid' which is required for OpenID Connect
options.Scope.Add("openid");

//options.Scope.Add("openid");
//options.Scope.Add("profile");
//options.Scope.Add("email");

options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.HttpContext.Response.Headers.Add("OIDC-DEBUG", "Redirecting to IDP"); // Add custom headers for debugging
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 500;
context.HandleResponse();
return context.Response.WriteAsync("Authentication failed: " + context.Exception.Message);
},
OnAccessDenied = context =>
{
// Capture and log more detailed error messages
context.Response.StatusCode = 403;
context.HandleResponse();
return context.Response.WriteAsync("Access denied: " + context.Result.ToString());
},
//OnAuthorizationCodeReceived = context =>
//{
// // Capture and log more detailed error messages
// context.Response.StatusCode = 200;
// context.HandleResponse();
// return context.Response.WriteAsync("Authorization code received: " + context.TokenEndpointRequest.Code);
//},

OnRemoteFailure = context =>
{
// Capture remote failures for better error handling
context.HandleResponse();

context.Response.Redirect("/error?message=" + context.Failure?.Message);
return Task.CompletedTask;
}
};


// JWT Signing algorithm based on metadata
//options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
//{
// ValidIssuer = authOptions.Authority,
// NameClaimType = "email",
// RoleClaimType = "role"
//};
});
and added these in the pipeline:
app.UseAuthentication();
app.UseAuthorization();
app.UseAuthentication();
app.UseAuthorization();
and this in the auth controller:
[AllowAnonymous]
[HttpGet("ologin")]
public IActionResult OLogin()
{
return Challenge(new AuthenticationProperties
{
RedirectUri = "https://localhost:4200" // <-- the angular app,


}, OpenIdConnectDefaults.AuthenticationScheme);
}
[AllowAnonymous]
[HttpGet("ologin")]
public IActionResult OLogin()
{
return Challenge(new AuthenticationProperties
{
RedirectUri = "https://localhost:4200" // <-- the angular app,


}, OpenIdConnectDefaults.AuthenticationScheme);
}
but no idea what next I saw that pkce word before in the AddOpenIdConnect options but didn't know what it does
MODiX
MODiX2mo ago
TeBeCo
good luck with all your research
React with ❌ to remove this embed.
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
K1lleR99
K1lleR992mo ago
feel free bro do u recommend some resources/courses to learn it? I'm still researching
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
K1lleR99
K1lleR992mo ago
yea I implemented normal jwt auth before the oauth is a new thing for me
Sossenbinder
Sossenbinder2mo ago
+1 to what TeBe mentioned, I'd have pointed you in the BFF direction as well. The alternatives for cross-domain cookies are usually JWTs as request headers but that comes with an entire new box of problems to discover If you can avoid it, try to find a working setup which allows you to use cookies (E.g. if the apps are on the same subdomain)
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server