AzureAD signout error mesage: "Hmm... we're having trouble signing you out." - asp.net

I created a web application using ASP.NET CORE, using the quickstart guide in the AzureAD portal. Signing in works, but when I attempt to log out, after about 5 seconds, I get the following message:
https://i.imgur.com/RhOGaf6.png
My app has been registered with the following redirect URIs:
https://i.imgur.com/CAnQpM8.png
With https://localhost:52410/signout-oidc as logout URL, and implicit grand for ID tokens enabled.
I can see in the browser debug menu under network that there is no response
from the logout URL. So, I'm assuming that the error message pop ups because the logout URL takes too long to respond.
Note: If I reload the browser page with the error I do logout.
So I'm wondering how can I resolve this error message?

I solved this error by adjusting the launchSettings.json file.
I adjusted the iisExpress setting in iisSettings to use SSL like so:
"iisExpress": {
"applicationUrl": "http://localhost:3110/",
"sslPort": 44321
}
On top of this, I adjusted the port of my own application to also use 3110.

It seems that the configurations are fine. Here is an working sample for your reference. You can check the code for signing out.
[\[HttpGet\]
public IActionResult SignOut()
{
var callbackUrl = Url.Action(nameof(SignedOut), "Account", values: null, protocol: Request.Scheme);
return SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme);
}
\[HttpGet\]
public IActionResult SignedOut()
{
if (User.Identity.IsAuthenticated)
{
// Redirect to home page if the user is authenticated.
return RedirectToAction(nameof(HomeController.Index), "Home");
}
return View();
}][1]

Related

Google Auth error getting access token in Blazor

I currently have a ASP.Net Core Web Api with Blazor WASM which can login successfully to Google OAuth using the component RemoteAuthenticatorView. My intention is now to pass the token I have to the web api, which hopefully can be used to authenticate with the web api. The issue is that TokenProvider.RequestAccessToken() produces the following error.
blazor.webassembly.js:1 Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 88.. See InnerException for more details.
System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 88.
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
var response = await Http.SendAsync(requestMessage);
}
Program.cs
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Local", options.ProviderOptions);
options.ProviderOptions.DefaultScopes.Add("email");
});
Any ideas? Is a scope missing? I can see id_token in Session storage... Perhaps any net 5 example of Blazor WASM and core web api?
Edit:
I see there is a network call made by RequestAccessToken to google auth, like if it were trying to authenticate again
Create a WebAssembly Blazor App standalone with individual accounts.
Replace the content in the appsettings.json file with the following code:
{
"Google": {
"Authority": "https://accounts.google.com/",
"ClientId": "11111111111-11111111111111111111111111111111.apps.googleusercontent.com",
"DefaultScopes": [ "email" ], // The Blazor WebAssembly template automatically configures default scopes for openid and profile
"PostLogoutRedirectUri": "https://localhost:44313/authentication/logout-callback",
"RedirectUri": "https://localhost:44313/authentication/login-callback",
"ResponseType": "id_token token"
}
}
Run your app, and click on the Login link...You're being redirected to Google' Login page. Authenticate with Google...You are being redirected to your app, the Login is changed into Logout, and your user name appears near it.
You may view the id_token and profile via the developers' tools.
How to retrieve the access token ?
Add the following code snippet to your Index page and run...
#page "/"
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
#inject IAccessTokenProvider TokenProvider
<p>#output</p>
<button #onclick="DisplayToken">Display Access Token </button>
#code
{
private string output;
private async Task DisplayToken()
{
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
output = token.Value;
}
}
}
Note: The code above is for demonstration purposes only (following your code sample). However, if you perform an HTTP call to your Web Api using the HttpClient service the access token is automatically retrieved and assigned to the Authorization header by the AuthorizationMessagelHandler object.

How do you setup special characters for Identity Core LoginPath?

I'm using ASP.NET Identity Core for authentication. I have an AngularJS SPA with a login route (UI-Router). My user's are getting routed to an escaped URL instead of the real URL.
My login path is set to "/#!/login", but my users are being routed to: "/%23!/login" which causes a 401 in the browser.
I've tried using System.Uri.EscapeDataString, System.Uri.EscapeUriString and without escaping at all with no luck.
Startup.cs
services.AddAuthentication()
.AddCookie(cookie =>
{
cookie.LoginPath = System.Uri.EscapeDataString("/#!/login");
})
AngularJS Route
.state('login', {
url: 'login',
views: {
'': { templateUrl: './Home/login.html', controller: "loginController" }
}
})
I've confirmed the server is generating a 302 response with the following location: "http://localhost:63939/%23!/login?ReturnUrl=%2Fadministrator". So the server is definitely escaping the "#!" and it is not something the browser is doing.
The only thing I've been able to figure out is to unescape the RedirectUri in the OnRedirectToLogin cookie authentication event. There has got to be a better way.
cookie.Events = new CookieAuthenticationEvents()
{
OnRedirectToLogin = context =>
{
context.Response.Redirect(System.Uri.UnescapeDataString(context.RedirectUri));
return Task.FromResult(0);
}
};

Single Page Application with adal.js and external web api (with AAD authentication)

I have an ASP.NET SPA with a adal-js based authentication, and an ASP.NET Web Api website with Azure Active Directory auth
Both websites are hosted on Azure, on different hostnames, say
https://foo.azurewebsites.com/ and https://fooapi.azurewebsites.com/
The Web Api website auth is configured as
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] },
Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
});
}
}
and Main SPA adal.js is initialized as:
var config = {
instance: "https://login.microsoftonline.com/",
tenant: "mytenant",
clientId: "client id of foo registration",
postLogoutRedirectUri: "https://foo.azurewebsites.com/",
cacheLocation: "localStorage"
};
authContext = new AuthenticationContext(config);
// Check For & Handle Redirect From AAD After Login
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
var errorMessage = authContext.getLoginError();
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
// Check if View Requires Authentication
if (!authContext.getCachedUser()) {
authContext.config.redirectUri = window.location.href;
authContext.login();
return;
}
The Tenant is the same for foo and fooapi, the client id is different (one for each app registration).
The authentication flow in the foo web app is performed successfully, but every http request to fooapi returns 401 unauthorized.
How can I make fooapi share the successful authentication of foo ?
Thank you for any hint
You can use the implicit grant flow in AAD so that an ID Token is received and sent in auth header when API call is made. See below links for the details and sample code.
https://azure.microsoft.com/en-gb/documentation/articles/active-directory-authentication-scenarios/#single-page-application-spa
https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp
How you acquire the access token for the web API?
To make sure the request successfully, you need to acquire the token using the resource you config in web API. You can pass the token from here to check whether the aud claim is equal to the value ida:Audience.
And also make sure the token is issued from the tenant you config in web API project since you didn't ignore the tenant verification.
Please configure your web point into endpoints and add it to initialization.
var endpoints = {`enter code here`
"https://yourhost/api": "b6a68585-5287-45b2-ba82-383ba1f60932",
};
adalAuthenticationServiceProvider.init(
{
// Config to specify endpoints and similar for your app
tenant: "52d4b072-9470-49fb-8721-bc3a1c9912a1", // Optional by default, it sends common
clientId: "e9a5a8b6-8af7-4719-9821-0deef255f68e", // Required
//localLoginUrl: "/login", // optional
//redirectUri : "your site", optional
endpoints: endpoints // If you need to send CORS api requests.
},
$httpProvider // pass http provider to inject request interceptor to attach tokens
);

Spark-java redirect - browser does not redirect

Ok, so I try to follow Spark documentation and I want to perform simple redirect in my Single Page Application. My code looks like this:
post("/users/login", (req, res) -> {
ObjectMapper mapper = new ObjectMapper();
User creation = mapper.readValue(req.body(), User.class);
User user = userService.getUser(creation.getLogin());
if (user.getPassword().equals(creation.getPassword())) {
req.session().attribute("userid", creation.getLogin());
System.out.println("OK");
res.status(201);
res.redirect("/index.html");
return "";
}
System.out.println("BAD");
return null;
} , json());
Basically, I have three static html files: registration.html, login.html and index.html. I read stuff concerning staticFileLocation so I added at the beginning of main function following line of code:
staticFileLocation("/public");
When I type correct login and password I find in the network view in Chrome that I have GET request with status 200, OK, to http://localhost:4567/index.html. However, the browser does nothing and does not redirect me to that page. Can you tell me what I am doing wrong?
EDIT:
Here's javascript code that handles log in on the client side:
app.controller('LoginUserCtrl', function($scope, $http) {
$scope.loginUser = {};
$scope.submitForm = function() {
$http({
method : 'POST',
url : 'http://localhost:4567/users/login',
data : $scope.loginUser,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).success(function() {
console.log("User logged successfully");
console.log($scope.loginUser);
}).error(function() {
console.log("Unknown error while logging user");
});
};
});
What's wrong is that you're redirecting to an HTML page in a post endpoint that's supposed to return Json data. You have to return a single json if authentication succeeded or failed, like {"auth": "OK"} or {"auth": "NOK"}, and decide where to redirect to from Javascript based in it's information.
It's because res.redirect will send a redirect http header(HTTP status values 301, 302, 303 and 307) to the browser,
but the browser only can redirect in get, NOT work in post or put or delete (Tested in chrome. Notice that a redirect request was sent by browser, but the page just not change...).
See:
http://www.alanflavell.org.uk/www/post-redirect.html

Logging in via Firebase Email/Password

I am trying to build a basic web application w/ user authentication via email/password registration using Firebase.
My setup right now includes a main.js file that consists of the following:
var dbRef = new Firebase('https://url.firebaseIO.com');
var authClient = new FirebaseAuthClient(dbRef, function(error, user) {
if (error) {
// an error occurred while attempting login
console.log(error);
} else if (user) {
// user authenticated with Firebase
console.log('User ID: ' + user.id + ', Provider: ' + user.provider);
} else {
// user is logged out
console.log('logged out!');
}
});
function next(){
window.location = 'index.html';
}
function test(){
authClient.login('password', {
email: email,
password: password,
rememberMe: true
},next());
// window.location = 'index.html';
}
I obtain email/password values from a form and login. That works. But as soon as I include a callback function to then redirect them to a new authenticated page, it no longer works. In fact, most of the time I get an "UNKOWN ERROR" response.
When I get to the next page, I am no longer logged in. If I remove the next() function and stay on the same page, it works - even if I then trigger the next function from the console. Is there a different way you are supposed to proceed to another page?
I'm pretty sure there is some sort of communication issue (possibly the login does not get a return before the page is switched?) because if I add a 1s timeout before the next function, it then works. But surely this is not best practice?
Thanks!
Per https://www.firebase.com/docs/security/simple-login-email-password.html, the authClient.login() method does not actually accept a callback, so the problem you're seeing is likely the result of navigating away from the current page before the callback is returned, as you suggested.
I would recommend doing the redirect in the callback you're passing during the instantiation of the auth client. (new FirebaseAuthClient(ref, callback)) and redirect if you detect a logged-in user. This callback will be invoked once upon instantiation with the current authentication state of the user, and then again any time the user's authentication state changes (such as on login or logout).

Resources