drashland/sinco

Support for 'Logging In'

Closed this issue · 8 comments

Summary

What:

Similar to Laravel's $browser->loginAs(User::first())

Why:

Majority of web apps use auth

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

  • Write documentation
  • Write unit tests
  • Write integration tests
  • Develop feature

Example Pseudo Code (for implementation)

public async loginAs(something: any): any {
  // ... how do we do this?
}

We should make a drash server to use, that uses auth so we have something solid, working and maintainable to test against

Something i use for a node app that uses a login system and csrf:

export async function loginAs ({ email, password }: { email: string, password: string }): Promise<ChaiHttp.Agent> {
  if (!email || !password) {
    throw new Error("Email or password params are empty.")
  }
  const agent = chai.request.agent(app);
  const response = await agent.get("/login")
  const html = response.text
  const csrf = html.split(/name="_csrf" value="/)[1].split("\">")[0]
  await agent
      .post('/login')
      .set("Content-Type", "application/x-www-form-urlencoded")
      .set("CSRF-Token", csrf)
      .redirects(0)
      .send({ email: email, password: password, _csrf: csrf });
  return agent
}
const agent = await loginAs({ email: "...", password: "..."})
const authenticatedResponse = await agent.get('/dashboard');
expect(authenticatedResponse.status).to.equal(200)

So we could do something similar, so say a user clicks a button on a login form, we save any cookies it adds etc, and keep the current browser session and just navigate to a new page

i think this will depend on #126

public async login(params: object) {
  // todo use Fetch domain to make request ie
  await this.location(params.loginUri);
  for (const [name, value] of params.body.entries()) {
    const elem = await page.querySelector('input[type="${name}"]');
    elem.value(value);
  }
  const submit = await page.querySelector(params.submitButtonSelector);
  page.expectWaitForRequest();
  await submit.click();
  await page.waitForRequest(); 
}
await page.login({
  loginUri: '/login',
  submitSelector: "#login",
  body: {
    email: '...',
    password: '...'

Multiple ways a uer can login, i think these are the only 2 ways in a deno app?

CSRF Tokens

As this is a header, maybe we can somehow set this on the page so every request sent from it, will use it? But the user needs to set this first somehow, eg to get to /users, they need the header present, and a valid value

Cookies

The user can set this on the page themselves, so i dont think we need to do anything here

Conclusion: user can do this themsleves, reagrding login forms (which includes headers), the user can go to a login form

User should be able to simply do this themselves and it would be convoluted for us to it, eg we'd:

  1. have to be given a uri for login page
  2. be given key value pairs, key = field name, value = value for input field
  3. button selector so we know what to click
  4. wait for this (though what if this is 3rd party eg google login, it takes to another page, something else to account for)
  5. allow a callback to be passed, to cover any things a user may need to do, eg maybe they click a login button, and it takes them to microsoft login, their callback would fill this in

agreed with closing this and passing it off to the user. sounds like this should be applied on top of and not within sinco. login forms hella vary and sinco would be convoluted very quickly. however, we could show how it can be done. more docs lol.

I am writing some docs on it though :) think it would be good, and to give you an idea, im starting it off with "Whilst Sinco doesn't provide much to help you log-in to apps, we will explain how you can do it via Sinco."