question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Missing JWT token with Safari (macOS and iOS)

See original GitHub issue

Is 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.

image

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:closed
  • Created 9 months ago
  • Comments:23 (13 by maintainers)

github_iconTop GitHub Comments

1reaction
surayya-MScommented, Feb 1, 2023

@erossini, thank you for providing a demo. I was able o reproduce the bug on a Mac using Safari.

1reaction
IvanJosipoviccommented, Jan 27, 2023

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

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Sign in with Apple missing email c…
Sign in with Apple missing email claim in the (JWT) identityToken.
Read more >
Https requests with Authorization not working via Safari
When an HTTP request made via safari is made to any url contains words like login , token , etc... safari automatically adds...
Read more >
Troubleshoot Renew Tokens When Using Safari
In some cases, renewing tokens with silent authentication does not work as expected with the latest version of the Safari browser. Recent versions...
Read more >
How To Fix Missing CSRF Token Error In Safari
Open Safari Preferences from the drop-down menu in the upper right corner or via the command + comma (⌘ + ,) shortcut. Click...
Read more >
Send a request to an API with JWT token from iOS ...
I'm running the web application on a Mac. The application is working fine with Microsoft Edge and Chrome but not with Safari. On...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found