directus / v8-archive

Directus Database API — Wraps Custom SQL Databases with a REST/GraphQL API
https://docs.directus.io/api/reference.html
507 stars 203 forks source link

Auth persist / storage not working #2339

Open DeMuu opened 5 years ago

DeMuu commented 5 years ago

🐞 Bug report

Auth persistance not working in Ember.js App.

Is this a regression?

Don't know

Description

Setting the storage does not seem to work. If I specifically set directusClient.config.storage = window.localStorage; it does create a localStorage entry but upon refreshing the page I am not authenticated. Please excuse if this is not a bug and I just manually need to do something here but to my understanding after reading the SDK Docs:

https://docs.directus.io/sdk/js.html#staying-logged-in

plus token refresh

If you use the login() method, you most likely don't need to touch >refresh< as it's being managed for you.

the SDK automatically handles session persistence.

🔬 Minimal Reproduction

new DirectusSDK({
      url: ENV.apiHost,
      project: "_",
      persist: true,
      tokenExpirationTime: 60 * 60 * 1000,
      storage: window.localStorage
    });

at a later time I call

client.login({
        email: "someemail",
        password: "somepassword",
        persist: true
      });

🔥 Exception or Error


HTTP 403

🌍 Your Environment

SDK Version: v6.0.0-alpha.2

Anything else relevant? ...

benhaynes commented 5 years ago

@rijkvanzanten — I assume this will be resolved by the new Auth flow?

rijkvanzanten commented 5 years ago

Nah, I think this was broken in either the typescript change or the auth flow changes. This is still officially supported though.

v5 is still the 'current' version in which this works, I recommend using that until v6 is out of alpha / beta

DeMuu commented 5 years ago

Thanks for the quick support and clarification! 👏 🙇

pgegenfurtner commented 5 years ago

This feature is not working for me with SDK Version 5.3.4.

I'm trying to use it within a next.js app

rijkvanzanten commented 5 years ago

@pgegenfurtner How are you trying to use it? Do you have a replicable example?

pgegenfurtner commented 4 years ago

I have an auth-service file in which I create a new instance of the sdk

const client = new DirectusSDK({
    url: API_URL
    project: 'PROJECT,
    storage: window.localStorage,
  });

and a login handler which looks like this:

export const handleLogin = async ({ email, password, persist }) => {
  const user = await client.login({
    email,
    password,
    persist,
  });
}

Nothing is added to the localStorage. Am I doing something wrong?

jesusmdy commented 4 years ago

I am also having that issue. I am triying to Sign In by the login() method but it doesn't generates a token. I was looking at the directus/app source code and i saw that it implements a field called mode: "cookie" So, i use a custom host in my computer http://api.directbay/directbay and when i tried to sign in from http://localhost:8080 it sents a cors error, that's why the cookie config isn't set to multiple host behavior. I used to have a custom plugin to evaluate auth status for route gards in VueJS. With the new Auth Flow it doesn't work anymore... How do we customize the auth cookie?

DeMuu commented 4 years ago

What's working for me with sdk-js 5.3.4 is the following. Please note that I just settled with this as soon as it worked so it might not be the best / correct solution (?):

new DirectusSDK({
      url: "API_URL",
      project: "PROJECT",
      persist: true,
      tokenExpirationTime: 60 * 60 * 1000,
      storage: window.localStorage
    });

and for logging in

login({
        email: "email",
        password: "password",
        persist: true
      })
jesusmdy commented 4 years ago

What's working for me with sdk-js 5.3.4 is the following. Please note that I just settled with this as soon as it worked so it might not be the best / correct solution (?):

new DirectusSDK({
      url: "API_URL",
      project: "PROJECT",
      persist: true,
      tokenExpirationTime: 60 * 60 * 1000,
      storage: window.localStorage
    });

and for logging in

login({
        email: "email",
        password: "password",
        persist: true
      })

Check this out: https://github.com/directus/api/wiki/Session-Auth-Flow

rijkvanzanten commented 4 years ago

The cookie mode is new, but that doesn't mean that the old JWT way of doing things should be broken.

ahuseyn commented 4 years ago

I am having same issue. I'm using Directus 8 and JS SDK 6. When I send request to auth/authenticate with mode: 'cookie' on Insomnia (Rest client) it returns header containing Set-Cookie directus-project-session=6WuPJo13QSqx4oU15yOd3F%2BovolGLetYUVA%3D%3A%3A7e343014f3291671664fd291b68f0903; path=/; expires=Sun, 29-Dec-2019 18:48:59 UTC; HttpOnly. But it is not working with js sdk. I tried both login and internal request methods as below:

client.login({
  email: name,
  password: email,
  mode: "cookie"
})
client.api.post("/auth/authenticate", {
  email: name,
  password: email,
  mode: "cookie"
})

Both requests done successfully and errorless but none of them set any cookie to the browser. I tried with Chrome, Chrome Dev and Opera. My Directus api url is: http://localhost/directus/public My Web app (client) url is: http://localhost:3000 So for now its impossible to benefit cookie mode.

rijkvanzanten commented 4 years ago

How do you run your app and api? They are normally the same thing (eg http://localhost/directus/public/admin/) so I'm guessing you're running this in a non-standard way.

rnwzd commented 4 years ago

I am having the same issues: with jwt it does not login, with cookie it sends a CORS error

ahmtaras commented 4 years ago

@rijkvanzanten Cookie mode does not write any cookies. Let's say I get data from api.example.com. My client side is another area. Systems using the Chrome infrastructure do not accept third-party cookies, unless permitted. When the Authentication method works properly, we can transmit cookies from the incoming request response and process it on the client side. What else can be done for this?

rijkvanzanten commented 4 years ago

When the Authentication method works properly, we can transmit cookies from the incoming request response and process it on the client side

Not sure what you mean by "When the auth method works properly". The cookie is set as httpOnly, meaning you can't read it from client side JS. This is by design to make it secured against xss attacks. If you run into any specific cors issues in the cookie, please open an issue on the API repo

ahmtaras commented 4 years ago

Sorry my English is weak.

Returns the token (if jwt mode is used) and the user record for the user you just authenticated as. Adsız

in cookie mode. You can return cookie information such as tokens. To bypass third-party cookies, we receive these cookies on the client side and we can print them as cookies.

Kematia commented 4 years ago

It seems to me that config.storage is undefined? It is defined correctly in the internalConfiguration and the api.

Screen Shot 2020-03-28 at 19 27 22

I tried to give a look at Configuration.ts in the sdk srouce but it's a bit above my paygrade for now, as you can see lol

Screen Shot 2020-03-28 at 19 30 13 Screen Shot 2020-03-28 at 19 30 19

The sdk is initialized as follows:

const directus = new SDK({
    url: "http://myip/",
    project: "myproject",
    mode: "jwt",
    persist: true,
    storage: window.sessionStorage
});
Kematia commented 4 years ago

Screen Shot 2020-03-30 at 16 14 26

I think I've found the issue, the storage is not passed correctly to the configuration constructor from the sdk init, I've hacked it to accept the storage passed from the initialization (ie: window.sessionStorage) and it now persits and works as expected.

I'll try and get together a PR but I'm not too sure of my ts skill and knowledge of the codebase, but maybe it could be a good starting point for an official fix?

@rijkvanzanten

e: open to have a chat on slack! e2: here you can see my hack

https://github.com/Kematia/sdk-js/commit/2468341cf9ecd0f9b3473bfa8aea4717c1ab9cd5

rijkvanzanten commented 4 years ago

Sounds good @Kematia! I'm around on Slack whenever you need me. It's time to spend some quality time cleaning up the SDK source a bit soon. I'm very busy on the app right now, so I'd love some help with that

Kematia commented 4 years ago

Guess this should fix the cookies on chrome? https://blog.chromium.org/2020/04/temporarily-rolling-back-samesite.html

rijkvanzanten commented 4 years ago

Fixed in directus/sdk-js#170

JonathanSchndr commented 4 years ago

@rijkvanzanten can you publish this to https://www.npmjs.com/package/@directus/sdk-js ?

rijkvanzanten commented 4 years ago

Published as v6.1.0

pgegenfurtner commented 4 years ago

Latest version on npm is v6.0.8 😅

rijkvanzanten commented 4 years ago

☹️

CI/CD is great.. until it's not.

JonathanSchndr commented 4 years ago

https://github.com/marketplace/actions/publish-to-npm :)

rijkvanzanten commented 4 years ago

yeah, we have that in place actually. Turns out one of the tests failed on the ci, but succeeded on my local ᕕ( ᐛ )ᕗ

rijkvanzanten commented 4 years ago

Ok published for real this time https://github.com/directus/sdk-js/runs/592744404?check_suite_focus=true

http://npmjs.com/@directus/sdk-js

tieftontier commented 4 years ago

@rijkvanzanten For me it is still not working to automatically persist jwt-token in localStorage with angular & directus-sdk. I have tried so many things, but on reload the authentication is gone. I have set up a test-project to make it as easy as possible:

export class DirectusService {
  private apiConfig: any = {};

  private apiClient;
  public get api(): DirectusSDK {
    return this.apiClient;
  }

    constructor() {
        this.apiClient = new DirectusSDK({
           url: environment.dbApi.url,
           project: environment.dbApi.project,
                   storage: window.localStorage as any,
                   mode: "jwt"
        });
    }

    public login(login, password) {
        const credentials: any = {
            email: login,
            password: password,
        };
        return this.apiClient.login(credentials);
    }
}

I tried to use storage: window.localStorage as any as I get the following error, when using storage: window.localStorage as proposed:

(property) IConfigurationOptions.storage?: IStorageAPI Type 'Storage' is not assignable to type 'IStorageAPI'. The types returned by 'getItem(...)' are incompatible between these types. Type 'string' is not assignable to type 'T'.ts(2322) Configuration.d.ts(68, 5): The expected type comes from property 'storage' which is declared here on type 'IConfigurationOptions'

Any help is highly appreciated here as I tried so many things until now to get it work! all the best, Tom

JonathanSchndr commented 4 years ago

@tieftontier try to add: persist: true

tieftontier commented 4 years ago

@JonathanSchndr I already tried persist: true but unfortunately nothing changed...

pierre-H commented 4 years ago

same problem :'(

michapixel commented 4 years ago

still a problem ...