#Angular is not saving cookies to the storage

230 messages ยท Page 1 of 1 (latest)

wooden tree
#

Hello! The backend servers sets 2 cookies, which are received in the response. The only problem is that they are not saved in the Cookie storage.
What's the magic to make them persist?

#

The post method looks like this: ```ts
@Injectable({ providedIn: 'root' })
export class ApiService {
constructor(
private http: HttpClient,
@Inject(API_URL) private api_url: string
) {}

post<T, D>(url: string, data?: D): Observable<T> {
return this.http.post<T>(${this.api_url}${url}, JSON.stringify(data), { headers: this.headers });
}

get headers(): HttpHeaders {
const headersConfig = {
'Content-Type': 'application/json',
Accept: 'application/json',
};

return new HttpHeaders(headersConfig);

}
}

autumn coyote
#

What's the url for the backend?

#

That looks like the angular url

#

Ah backend is 7175

#

So yeah cookies are set for that tho, not 4200

#

Are the cookies sent across correct? That's all that matters.

#

You probably need withCredentials tho

wooden tree
#

withCredentials might be the problem indeed

#

Still not working

#

This is the configuration on the backend

#

Damn, my browser blocks them

wooden tree
#

This is the default Chrome settings, this means my auth is useless

#

Third-party cookies get blocked

#

Okay I must switch to Auth0

autumn coyote
#

We also use third party cookies

#

And based on what we discussed, the setup would be the same

#

Ensure api and app share the same domain, cookies are no longer third party then

#

That's all why we don't do cookies by default in SPAs

#

Its the best, but not always easy or even possible depending on your setup

wooden tree
#

Is it still considered a good practice to enable third party in the browser during development? Outside development, the app and backend would need to be deployed under the same domain

#

I mean, having the same domain should not introduce complications. If it is possible to set up the same domain on 2 different cloud instances (never done that) then I do not see any problem

rapid verge
#

There's usually a CDN/gateway in front of them, otherwise you'll end up with different IPs

#

(don't remember if it'd be considered third party)

wooden tree
#

Then it is a win win

wooden tree
#

Would I encounter the same problem if I managed login on the backend with Auth0 instead of the Universal Login?

wooden tree
#

๐Ÿ˜‚

autumn coyote
#

Your API and FE still need to be on the same domain

#

Every cookie that isnt on the same domain causes the same issue

#

You can avoid it by not using cookies.

#

Which has its own set of consequences.

#

Which, again, is why our SPA SDKs do not use cookies.

#

But still cookies is superior, as long as they are HTTP ONLY

#

I think it can be a challenge tho for local development.

#

(But I assumed you had already figured that out as it sounded like u had the HTTP ONLY cookie setup working with your own implementation)

wooden tree
#

For development it works if I allow thrid party cookies, now I receive them

autumn coyote
#

Yeah

#

Thats true.

#

But is that a stting u can configure per domain?

#

Or is it for the entire browser ?

#

(I have never looked at the settings ๐Ÿ˜„ )

rapid verge
#

It can be set per domain

autumn coyote
#

Great!

wooden tree
#

yes, but for now I could not add the localhost:port, did not work

rapid verge
#

Looks like api.x.tld and x.tld works though, with cookies

wooden tree
#

that is perfect

rapid verge
#

If you use something like cloudfront you can easily do * going to your frontend and /api going to your backend too

#

(cloudfront, nginx, cloudflare, etc)

wooden tree
#

for now don't deploy it, but do implementations to be easily configurable. For example, factory methods construct the right instances based on the current environment.

rapid verge
#

Hm not sure what you mean, all this is fairly external to the app

#

Or you mean you have a configurable API endpoint base URL?

#

Because that essentially boils down to having a string or Observable<string> (or URL)

#

(please don't use Angular environments ๐Ÿฅฒ)

wooden tree
#

Did I get it right? If they run on the same domain then the sameSite should be strict?

rapid verge
#

same-site means the base domain is the same, so www.x.tld to api.x.tld would work too

wooden tree
#

perfect

wooden tree
rapid verge
#

(it's a bit more complex than that because there's some kind of list of what counts as a tld and it's not just actual tlds, iirc stuff like github.io counts as a "tld" too but still)

rapid verge
#

Environments can have their use but it's more a build configuration than a deployment environment, sadly the naming made it.. drift

autumn coyote
#

I believe u should use runtime configuration and not compile time configuration

autumn coyote
#

Which is ... probably worse.

#

(and dont get me wrong, I like react. But the introduction of .ENV files is just confusing for people that arent aware there is no concept of environment variables in the browser)

rapid verge
#

It sure is

#

It's also why new devs take the first day trying to get environment variables working ๐Ÿ˜„

#

(first day for the good ones)

autumn coyote
#

๐Ÿ˜„

autumn coyote
#

๐Ÿ˜„

rapid verge
#

The holy conf crusade

wooden tree
#

For now I only have env configuration on the backend which happens on build. Now that the Cookie differs based on the environment I am wondering if I should do it like this:

#

But I think I should not

#

this does not happen on build time, rather when creating new instances

autumn coyote
#

ah

#

thats what you said

#

I should read everything

#

lol

wooden tree
#

This is how I did with token settings. In prod the secret would normally be stored securely in a vault and would be accessible upon request. So that would require a different implementation to set the fields

#

Is this good or can be done better?

autumn coyote
#

Iirc that can be done better

#

I mean, u can auto-map config sections to classes

#

and no need to manually map them

#

Let me try and find that

wooden tree
#

You mean in the Program.cs?

#

I know a one liner option exists there

autumn coyote
#
builder.Services.Configure<DevAccessTokenSettings>(
    builder.Configuration.GetSection("JwtSettings"));
#

Next, whenever u need it u can just inject it

private readonly DevAccessTokenSettings _options;

    public SomeClass(IOptions<DevAccessTokenSettings> options)
    {
        _options = options.Value;
    }
wooden tree
#

Yes, and what happens when the environment is not development? The values would not come from a file

autumn coyote
#

๐Ÿ˜„

#

You are solving problems that do not exist.

#

If u have a FOO thing in your appsetting

#

AND you define a FOO thing in your environment variable

#

on the server

#

the env variable wins.

#

and the appsetting is ignored.

#

Thats why u use the concept of "Configuration"

#

U dont just read from the appsettings file

#

u read from the .NET configuration system

#

which has different sources it reads from

wooden tree
#

What is FOO?

autumn coyote
#

FOO is a random string

#

So u have JwtSettings:AccessToken:Issuer, right?

wooden tree
#
"AccessToken": {
  "Issuer": "https://localhost:7151",
  "Audience": "https://localhost:7151",
  "SecretKey": "secret",
  "ExpirationInMinutes": 15,
  "ClockSkewInSeconds": 5
},
autumn coyote
#

If u read the link I shared, what u want is to define an environment variable on the production server like this: JwtSettings__AccessToken__Issuer and its value will override the one in appsettings.

wooden tree
#

I understand, evrything will be loaded from appsettings

autumn coyote
#

So development will use the appsettings.

#

but on production it will ignore that.

autumn coyote
#

Configuration reads from all of that

#

appsettings is just the first layer.

#

If u define ANYTHING with the SAME NAME in any of those other laters, it overrides it.

#

So what u want to do is just use this:

builder.Services.Configure<JwtSettings>(
    builder.Configuration.GetSection("JwtSettings"));

then, by default everything uses appsettings.json. Now lets say you want to use a different Audience on your deployed version, then you just define an environment variable on that server: JwtSettings__AccessToken__Audience and set it to something else.

wooden tree
#

Oh so probably there is an option before build to get the Secret key from the Vault that overrides the default one. Or simply inserts if if it was not specified

autumn coyote
#

But the summary is

#

U do this in program.cs

#
builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new DefaultAzureCredential());
#

and it auto connets things for u. All u then need to do is ensure things use the correct name.

wooden tree
#

Did not check the 2nd link, sorry

autumn coyote
#

(I mean, cponnecting AzureKeyVault is a bit more complicated, but in essence that is how u connect it to the Configuration)

#

You should not worry about environents, but just straight up read from the Configuration.

#

I have deployed tons of .NET API's like that to numberous of environents

#

(e.g. I have worked in horror set ups were we had: DEV, TEST, QA, PREPROD, PROD and DEMO environments)

#

And I was able to use different configs for all of those without needed what u tried.

wooden tree
#

Impressive, I just went Java style here :c

autumn coyote
#

The configuration in aspnetcore is cool

rapid verge
wooden tree
#

it is my bad anyway

#

newbie problems

autumn coyote
#

Doesnt matter

#

All good

#

Just sharing so u know it exists

#

there is too much out there to know it all

wooden tree
#

I would need the DevAccessTokenSettings in the AddJwtBearer

#

I do not think it is possible to do that

autumn coyote
#

I think there are solutions for that

#

but might be a bit awkward yeah

#

But you are reinventing the wheel here

#

See: Simplified configuration for the JwtBearer middleware

#

with .NET7, JwtBearer can auto-map to appsettings.

#
// appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Authentication": {
    "Schemes": {
      "Bearer": {
        "Authority": "https://{DOMAIN}",
        "ValidAudiences": [ "{AUDIENCE}" ],
        "ValidIssuer": "{DOMAIN}"
      }
    }
  }
}
#

If u use that structure

#

(its auth0 blog psot but unrelated to auth0 specifically in this case)

wooden tree
#

Thank you.

wooden tree
autumn coyote
#

๐Ÿ˜‚ right

autumn coyote
#

Your own snippet literally says AddJwtBearer

autumn coyote
#

So u can use what I shared if that snippet is what u are using

wooden tree
#

Sorry, I am struggling with a configuration. Did not change the JwtBearer yet

#

It has null value

#

Isn't this code snippet correct?

autumn coyote
#

Can u shw appsettings

wooden tree
#
  "EmailEncryption": {
    "Key": "test_key",
    "InitializationVector": "test_vector"
  },
#

And the class: ```ts
public class DevEmailEncryptionSettings
{
public string EncryptionKey;
public string InitializationVector;
}

#

well I see a problem

autumn coyote
#

Also want to get rid of all the Dev prefixes, but thats unrelated

wooden tree
#

One variable name is not the same

autumn coyote
#

Yeah the name needs to match

wooden tree
#

๐Ÿ˜‚

autumn coyote
#

๐Ÿ˜„

#

Does it work now ?

wooden tree
#

no

autumn coyote
#

So whats bnot working? Whatsnull?

wooden tree
#
    private readonly DevEmailEncryptionSettings _emailEncryptionSettings;

    public EmailEncryptionHelper(IOptions<DevEmailEncryptionSettings> emailEncryptionSettings)
    {
        _emailEncryptionSettings = emailEncryptionSettings.Value;
    }
#

IOption cannot be instantiated, I did not register it with AddSingleton or AddScoped

autumn coyote
#

Does it help if u make it a property instead of a field? ๐Ÿค”

#

Yeah you should make it properties.

#

(explained in the link I shared ๐Ÿ˜› )

wooden tree
autumn coyote
#

a field is

#

public String Test

#

a property is

#

public String Test { get; set; }

wooden tree
#

๐Ÿ‘ works like a charm

#

I think since .NET 7 there is a warning when a string property is not initialized

#

Should any of these suggestion be used to suppress the warnings?

autumn coyote
#

public String Test { get; set; } = String.Empty

wooden tree
#

Wow, only 3 files remained from 9, clean

rapid verge
#

Now just gotta delete the 3 remaining ones ๐Ÿ˜Ž

#

(that's how no-code works right?)

wooden tree
#

๐Ÿ˜‚

wooden tree
#

UX question: Having a confirm password input field limits the chances of a user making a typo in his password. The downside is that he needs to type more. What are your thoughts on this?

autumn coyote
#

My opinion?

#

A password should not be something u type.

#

So a confirm field should be useless

#

Sure if u use ILoveBrocolli and u mistype, your problem

#

It should be Ahfi&โ‚ฌ++uek__ to begin with

#

(which i do not even want to type twice, why ask me to paste it twice)

wooden tree
#

Alright, thanks

#

I will remove it

autumn coyote
#

Be sure to add a toggle

#

To show it tho

#

Like a little eye icon

wooden tree
#

I have that

autumn coyote
#

Sorry

#

Reading and watching isn't my specialty clearly

rapid verge
#

The form has better eyes than yours

wooden tree
#

How do I know if a service should be registered with AddScoped or AddSingleton? When a service is used in a Controller is it right away AddScoped?

autumn coyote
#

Which u generally dont need.

wooden tree
#

Understood, thanks

autumn coyote
#

Do u know the difference ?

wooden tree
#

I know what the singleton pattern is. AddSingleton creates only one instance which will be shared across the app

#

right?

autumn coyote
#

Scoped is the same, but per request

#

so every request a single instance is used

#

but destroyed as the request ends

#

So two simultaneous requests use two seperate instances