Authentication and Cookies when using Custom Function

Hi,

I am struggling nearly all day to get authentication to work on custom lambda functions.

My fetch won’t add cookies and therefore authentication is not working. I have tried to set access policies and credentials on both web and api side, taking graphql api calls as a reference. But my function is not able to access context.currentUser, since Cookies are missing. If I copy them from a graphql to my custom function fetch, it works.

Since my web and api side run on different sub domains I also tried to set the cookie Domain value to the domain. However, when I am doing this, the user cannot be logged in anymore. I also tried using SameSite ‘Lax’ as property. But somehow reauthentication does not get a new token and therefore does not sign in.

Web

fetch(window.RWJS_API_URL + '/myFunc', {
    method: 'PUT',
    headers: {
      ...fetchConfig, // taken from useFetchConfig
      'Content-Type': 'text/plain',
    },
    credentials: 'include',
    mode: 'cors'
    body,
  })

Api

(use of middy is not necessary i think. I tried all kinds of options)

const myFunc = async (event: APIGatewayEvent, context: Context) => {
  if (isAuthenticated()) { 
 // not reaching this part
  } else {
    logger.error('Access to myFunc was denied')
    return {
      statusCode: 401,
    }
  }
}

export const handler = middy()
.use(cors({ credentials: true, origin: '*' })
.handler(
useRequireAuth({
  handlerFn: myFunc,
  getCurrentUser,
  authDecoder: createAuthDecoder('session'),
}))

Auth-Cookie Settings

cookie: {
      name: 'session',
      attributes: {
        HttpOnly: true,
        Path: '/',
        SameSite: process.env.NODE_ENV === 'development' ? 'Lax' : 'None',
        Secure: process.env.NODE_ENV !== 'development',
        Domain: process.env.NODE_ENV === 'development' ? 'localhost' : 'myDomain.com'
      },
    }

I am working on a serverful environment using dbAuth.
I am wondering if there is still a piece that I am still missing. Currently I think the issue is the failing reauthentication on login. auth/getToken returns statusCode 200. I am not sure how this is connected to the Domain setting. Without the Domain setting login seems to work, but custom functions do not.

Btw. I tried to add some documentations on custom functions, because it is quite vague in some situations.

Error when calling backend throws at authEnrichedFunction. This seems to happen already on network request with method OPTIONS which should be the preflight:

2024-12-06T17:02:15.506919651Z {"level":50,"time":1733504535506,"reqId":"req-2n","err":{"type":"UnauthorizedError","message":"Unauthorized","stack":"UnauthorizedError: Unauthorized\n    at myFunc (/app/api/dist/functions/myFunc/myFunc.js:114:11)\n    at authEnrichedFunction (/app/node_modules/@redwoodjs/graphql-server/dist/functions/useRequireAuth.js:59:20)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)","status":401,"statusCode":401,"expose":true},"msg":"Unauthorized"}
1 Like

This is an interesting issue. I’ve been doing some other dbAuth cookie related work lately. I’ll see if I can find some time tomorrow to take a look.

Have you tried both on localhost and when deployed? Do they both fail?

And, just because I’m curious, why are you not using gql here?

Hi Tobbe!
Please wait with it!
I noticed yesterday at the ende, that I had Node_env set to development on my server for logging reasons. So i have to go through some options again. Maybe it works then.

We wanted to use custom functions for validation or also as a proxy for some data. Since we wanted to use a simple fetch instead of using a full cell setup.

Enjoy your weekend! :blush:

:saluting_face:

Personally I find useQuery() or useLazyQuery() to be about as easy to work with as fetch(), but with the extra benefits of using all the gql goodies we already have in place :slight_smile:

Hi @Tobbe ,

we also use useQuery or useLazyQuery, but in this case there might be lots of requests, since we want to use the function as a proxy to get tiles for a mapping application.

I think I got it to work now. I am going to share some of my experiences here:
I can manage to login when setting Domain on cookies now, but it seems it is only possible, when the Domain is shared by the subdomains of web and api. So in my case I have i.e.
web.myDomain.com and api.myDomain.com. Setting Domain to web.myDomain.com does not work, but using myDomain.com does work.

This would be the configuration:

Auth-Cookie Settings

cookie: {
      name: 'session',
      attributes: {
        HttpOnly: true,
        Path: '/',
        SameSite: process.env.NODE_ENV === 'development' ? 'Strict' : 'None',
        Secure: process.env.NODE_ENV !== 'development',
        Domain: process.env.NODE_ENV === 'development' ? 'localhost' : 'myDomain.com'
      },
    }

Within my fetch function I tried to add fetchConfig, but it seems I should not add it to the fetch. Adding it causes problems. So it is plainly this:

Web Request

fetch(window.RWJS_API_URL + '/myFunc', {
    method: 'POST', // PUT is not possible
    headers: {
      'Content-Type': 'text/plain',
    },
    credentials: 'include', // same-origin does not work
    mode: 'cors'
    body,
  })

And of course… set NODE_ENV to production :sweat:

Now I can do an authenticated request.

I have added some remarks to the PR documenting custom functions. let me know if this suits you:

1 Like

@Tobbe do you know by any chance how to add additional information to the context in a custom function equivalent to the graphql approach? createGraphQLHandler({ context: setContext })

it seems it is just:

const handler = async (event, context)=> {
 context.foo = 'bar'
...
}

I’ll properly review your PR today. I will look into the context question as well when I do.