Inject the current user in a TS function

Hey there !

We’re using OSDK in native mobile apps (+ web clients as well)

I have a typescript function that executes a certain logic for a user.
For obvious security reasons, I’d like this logic to only be applied to the user that is currently authenticated through the OSDK (using a Foundry token).

Is there a way to, inside a typescript function (a Query one more specifically), inject the current user ? (A possible “workaround” would be to have a userId as a param for the said function, but that means anyone can call the function with any id, and I’d like to avoid that)

Thanks a lot !

1 Like

I am guessing from your question that you are using confidential client (service user) and not a public client application?
If you create a public client application it will require each user to have a Foundry user, and will take the user through a simple login process, after-which each call would be made on behalf of the user.
I am not sure how you plan to use the user context in the functions you call but in the process above you are gurenteed that the function is executed using the user’s permission.
Note that if you are using npm create @osdk/app@2.1.0-beta.19 you will have the option to generate an Expo (React Native) template to use with OSDK which might help you as a reference.

1 Like

Thanks for your reply!

Hmm seems like my initial post wasn’t clear enough so let me explain a bit further:

  • Mobile app: using client OSDK ( so not a service user, a public client)

  • TS repo on foundry: typescript functions, exposed to clients through OSDK.

Here’s a fictional scenario + pseudo code to explain the situation:

I want to expose a function that executes a certain logic depending on the current user, for example creating a customer in an external system.

So we’re gonna have a function like this:

async createCustomerInExternalSystem() {
  const theInfoIwant =  await fetch("externalSystemUrl/customers", { method: "POST" })
  return theInfoIwant
}

Now image the externalSystemUrl/customers endpoint requires a certain information from the user, for example his email. I’d then like to do something like this:

async createCustomerInExternalSystem() {
  const currentUser = getCurrentUser() // gotten from the token that's in the http call for this method
  const theInfoIwant =  await fetch("externalSystemUrl/customers", { 
      method: "POST"; 
      body: { 
           email: currentUser.email
      } 
  })
  return theInfoIwant
}

or even using injection if possible as a few backend frameworks do, something like this:

 // gotten from the token that's in the http call for this method
async createCustomerInExternalSystem(currentUser?: Principal) {
  const theInfoIwant =  await fetch("externalSystemUrl/customers", { 
      method: "POST"; 
      body: { 
           email: currentUser.email
      } 
  })
  return theInfoIwant
}

Then, the mobile app would call this function using the public OSDK client:

client(createMeasurementV2).applyAction()

and the TS function would get the current user based on the authenticated user from the app, as he sends a Foundry token in the request.

I hope it’s a bit clearer now.
I currently can’t really inject the current user into a function.
Is that currently possible ?

Thanks !

So you want the current user context in the functions.
You have 2 options for this:

  1. If you are using an action, in the rules page you can pick current user as an input parameter and not data coming from the OSDK client, then the action can use the client id to do whatever you want.
  2. You can use PSDK to get the current user details in the OSDK application and send it as parameter to the function without requiring the user to set it.
import { getCurrent, User, profilePicture } from "@osdk/foundry.admin/User";
import { platformClient } from '@/Foundry/client';

const PsdkUser: React.FC = () => {
    const [user, setUser] = useState<User | undefined>();

    const getProfile = useCallback(async () => {
        const result = await getCurrent(platformClient, { preview: true });

HTH,

  • Regarding option 1: I need my function to return things, so it’s not an Ontology Edit Function, but a Query. (@Query({ apiName: ...})), which means it’s not really an action, in the sense that queries can only be edited from the repo, not from the UI, and rules can’t be configured.

  • Regarding option 2: that means there’s an exposed api endpoint that takes a user param, which to me seems like a security issue as anyone with a token can call the endpoint (in our context a token is easily obtainable as it’s a B2C app). For now I’m just using a usedId as a param for that function, which reduces the risk, ideally I’d just get the user calling the function inside the TS function, but I’m guessing from your answer that it’s not currently possible ?

You are correct on #1 I just wasn’t sure on what was your use case.
Regarding #2 this is less of an OSDK question and more of a Functions questions but you can’t get the calling user id from a function (Query) you can have a parameter of the userID and then use that parameter to query for other user’s attributes like email so you reduce the risk but not eliminate it.

import { Function, Users } from "@foundry/functions-api";

export class UserFunctions {
    @Function()
    public async getUserEmail(userId: string): Promise<string | undefined> {
        try {
            const user = await Users.getUserByIdAsync(userId);
            return user.email;
        } catch (error) {
            console.error(`Error fetching user: ${error}`);
            return undefined;
        }
    }
}

BTW, it does make sense to make it into a function backed action and not use a Query because query do not expect to have a side effect of writing into some system.
if you make it into an action like I suggested in #1 you both make it clear that this will write data, you get the current user for free and you are able to write the result of the request.
I would look into webhook for this.

Yeah for now I’m using a userId as parameter, so I’m reducing the risk but not eliminating it. So you’re saying there’s currently no way to eliminate it (for example a mechanism that injects the current user in the function) ?

The reason I’m using a query and not an Ontology Edit Function is that I need the call to immediately return something (ephemeral payment data that should not be stored anywhere), and since Queries can return and OEF can’t, I have to use queries.

tagging functions as you want to get these details in Functions.

1 Like