Serverless Function returning 404 - trying to update user role (re: identity)

SiteID - c8edef73-4f33-49ab-9dee-3894850d6122
Site Name - superb-cat-8482c1

I am attempting to set up a serverless function that simply adds a user role to all users on user creation - since I want to include users who are using google, I am using the workaround which I found on another thread (create a function and called it the webhook).

The function is executing when it should, but I’m getting a 404 as the response when making the call to update the user. Below is a snippet of code where I create the target url and then the response that I’m receiving. This would indicate that I have the target url wrong, but I have checked all the documentation that I can find and it looks to be correct.

Please advise -
Thanks

let user_url = `${identity.url}/admin/users/${netlifyUserID}`
const updatedUser = await fetch(user_url, {

INFO Response {
size: 0,
[Symbol(Body internals)]: {
body: PassThrough {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 5,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: true,
[Symbol(kCapture)]: false,
[Symbol(kCallback)]: null
},
stream: PassThrough {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 5,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: true,
[Symbol(kCapture)]: false,
[Symbol(kCallback)]: null
},
boundary: null,
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
type: ‘default’,
url: ‘https://data.timestable.io/.netlify/identity/admin/users/08ae684b-cefc-41e1-8a29-9e00f8e5e9fa’,
status: 404,
statusText: ‘Not Found’,
headers: {
age: ‘0’,
‘alt-svc’: ‘h3=“:443”; ma=2592000,h3-29=“:443”; ma=2592000’,
connection: ‘close’,
‘content-length’: ‘35’,
‘content-type’: ‘application/json’,
date: ‘Sat, 06 May 2023 23:44:13 GMT’,
server: ‘Netlify’,
‘strict-transport-security’: ‘max-age=31536000’,
via: ‘1.1 google’,
‘x-nf-request-id’: ‘01GZSQ77ZMX3TZNKB9H4CCS0D0’
},
counter: 0,
highWaterMark: 16384
}
}

If you’re using a webhook, I believe you should be simply able to modify the user object and return the use with the new role as a JSON body. That works for normal logins, but I don’t recollect if it works for Google login as well. Most likely it does.

However, if you want to go down this way, which I feel would fail even if you end up moving past this 404. To solve the 404 however, you need to pass the temporary admin token as shown here: GitHub - netlify/gotrue-js: JavaScript client library for GoTrue

Speficially, this part:

const userUrl = `${identity.url}/admin/users/${userID}`;
const adminAuthHeader = "Bearer " + identity.token;

  try {
    return fetch(userUrl, {
      method: "PUT",
      headers: { Authorization: adminAuthHeader },

Thanks - I am currently using the bearer token for authorization … below is the full code of the function

import { Handler } from ‘@netlify/functions’;
import fetch from ‘node-fetch’;

const handler: Handler = async (event, context) => {
console.log(‘the function was called’);
try {

json_body = JSON.parse(event.body)
body_user = json_body.user
netlifyUserID = body_user.id

// send a call to the Netlify Identity admin API to update the user role
const { identity } = context.clientContext;
console.log('identity - ',  {identity});
let user_url = `${identity.url}/admin/users/${netlifyUserID}`
console.log('user_url = ', user_url)
const updatedUser = await fetch(user_url, {
  method: 'PUT',
  headers: {
    // note that this is a special admin token for the Identity API
    Authorization: `Bearer ${identity.token}`,
  },
  body: JSON.stringify({
    app_metadata: {
      roles: ['Approved'],
    },
  }),
});

console.log(updatedUser)
return {
  statusCode: 200,
  body: JSON.stringify(updatedUser),
};

} catch (error) {
console.log(error)
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};

export { handler };

Are you sure the user exists in the body? According to the documentation, it exists in the context.

A field definitely exists at body.user.id

What field would be the relevant field in the context? I have tried context.clientContext.custom.netlify thinking that might work but it didn’t work either.

Ok - you are correct and I think that I have identified the underlying issue. When this function fires, it doesn’t have a “user” included in the clientContext. It has “identity” but no “user”

can you tell me how to make sure that the context includes user? I thought it would all be included as long as identity was enabled.

In Netlify, when an Identity service is active for a site, functions running on that site have access to an identity and a user object in the clientContext. You can access the user object in the clientContext using the following code:

exports.handler = async function (event, context) {
  const { identity, user } = context.clientContext;
  // Do stuff and return a response...
};

The user object is present if the function request has an Authorization: Bearer <token> header with a valid JWT from the Identity instance. In this case, the object will contain the decoded claims.

Source: Functions and Identity