Missing JWT token with Safari (macOS and iOS)
See original GitHub issueIs there an existing issue for this?
- I have searched the existing issues
Describe the bug
I had this behaviour roughly a year ago. Now, in my new application, I’m facing the same issue, but the old solution didn’t work. So, I have a Blazor application with NET6. When the application calls the API, I add the user token in the Header
.
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
To retrieve the user token, I have a function that read the token from the cache or from IAccessTokenProvider
.
IAccessTokenProvider _accessToken;
private async Task<AccessToken> RequestUserToken()
{
try
{
var tokenResult = await _accessToken.RequestAccessToken();
tokenResult.TryGetToken(out var token);
Console.WriteLine(token);
return token;
}
catch (AccessTokenNotAvailableException aex)
{
throw new ApplicationException($"Exception {aex}");
}
catch (Exception ex)
{
throw new ApplicationException(
$"AccessTokenNotAvailable Exception Exception {ex}");
}
}
The application sends successfully requests to the API from Windows and Android. When I run the application on macOS and iOS devices, the token is not found and then there is an error.
To debug this issue, I run the web application on a Mac. On the Mac, the application is working fine with Microsoft Edge and Chrome but not with Safari.
On iPhone and iPad, this issue is present on Safari and Chrome. It works fine on Microsoft Edge.
Previously, I checked that on macOS and iOS the token could be read only once and then the browser forgets it.
I received a suggestion from the Microsoft Forum to add in the ws:
and wss:
like that
app.Use((context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
MustRevalidate = true,
NoCache = true,
NoStore = true,
};
string oidcAuthority = builder.Configuration.GetValue(typeof(string), "oidc:Authority").ToString();
string mainUrl = "https://*.mydomain.com/";
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("Content-Security-Policy",
$"default-src 'self' {mainUrl} {oidcAuthority} 'ws:' 'wss:' " +
"https://code.cdn.mozilla.net " +
#if DEBUG
"https://dc.services.visualstudio.com " +
#endif
"https://api.mydomain.com " +
"'unsafe-inline' 'unsafe-eval'; " +
$"script-src 'self' {mainUrl} 'unsafe-inline' 'unsafe-eval'; " +
$"connect-src 'self' {oidcAuthority} https://code.cdn.mozilla.net https://api.mydomain.com;" +
$"img-src 'self' {mainUrl} data:; " +
$"style-src 'unsafe-inline' {mainUrl} " +
"https://code.cdn.mozilla.net " +
";" +
"base-uri 'self'; " +
"form-action 'self'; " +
"frame-ancestors 'self';");
context.Response.Headers.Add("Referrer-Policy", "same-origin");
context.Response.Headers.Add("Permissions-Policy", "geolocation=(), microphone=()");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
context.Response.Headers.Add("SameSite", "Strict");
return next.Invoke();
});
Add more details
I’m creating application with Blazor in NET6. To call the API via an Azure API Management, I have to pass a token in the request adding
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
In this request, I have to pass the token that comes from an Identity Server
. So, first, the user has to authenticate to the identity server and then receives the JWT token.
The configuration is
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("oidc", options.ProviderOptions);
options.UserOptions.RoleClaim = "role";
})
.AddAccountClaimsPrincipalFactory<MultipleRoleClaimsPrincipalFactory<RemoteUserAccount>>();
builder.Services.AddAuthorizationCore();
Also, to apply the security, I add in the Program.cs this lines
app.Use((context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
MustRevalidate = true,
NoCache = true,
NoStore = true,
};
string oidcAuthority = builder.Configuration.GetValue(typeof(string), "oidc:Authority").ToString();
string mainUrl = "https://test.mywebsite.com/";
#if DEBUG
mainUrl = "https://localhost:7040";
#endif
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("Content-Security-Policy",
$"default-src 'self' {mainUrl} {oidcAuthority} " +
"https://code.cdn.mozilla.net " +
#if DEBUG
"https://dc.services.visualstudio.com " +
#endif
"https://api.myapi.com " +
"'unsafe-inline' 'unsafe-eval'; " +
$"script-src 'self' {mainUrl} 'unsafe-inline' 'unsafe-eval'; " +
$"connect-src 'self' {oidcAuthority} https://code.cdn.mozilla.net https://api.myapi.com;" +
$"img-src 'self' {mainUrl} data:; " +
$"style-src 'unsafe-inline' {mainUrl} " +
"https://code.cdn.mozilla.net " +
";" +
"base-uri 'self'; " +
"form-action 'self'; " +
"frame-ancestors 'self';");
context.Response.Headers.Add("Referrer-Policy", "same-origin");
context.Response.Headers.Add("Permissions-Policy", "geolocation=(), microphone=()");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
context.Response.Headers.Add("SameSite", "Strict");
return next.Invoke();
});
So, after that I can read the JWT token with this code:
IAccessTokenProvider _accessToken;
private async Task<AccessToken> RequestUserToken()
{
try
{
var tokenResult = await _accessToken.RequestAccessToken();
tokenResult.TryGetToken(out var token);
Console.WriteLine(token);
return token;
}
catch (AccessTokenNotAvailableException aex)
{
throw new ApplicationException($"Exception {aex}");
}
catch (Exception ex)
{
throw new ApplicationException(
$"AccessTokenNotAvailable Exception Exception {ex}");
}
}
The application is working on Windows for any browser. On iOS and macOS I can read the token if I use Safari. It is working if I use Microsoft Edge and Chrome.
Do you have any idea how can I fix it?
Issue Analytics
- State:
- Created 9 months ago
- Comments:23 (13 by maintainers)
@erossini, thank you for providing a demo. I was able o reproduce the bug on a Mac using Safari.
I am also seeing this problem in Blazor in .Net 7. 95% of the exceptions are from Macs.
NuGet Packages = 7.0.2 SDKversion = 7.0.102