Azure Functions Node.js typescript global variable

161 views Asked by At

I have some node.js Azure Functions (httptriggers) coded with Typescript that I secure with a jwt token. After validating my token at the beginning of the funtion, I'd like to store it globally so I can use it in all my child functions. But I'd like my token to be valid only for the current Invokation Context. I don't want to pass the token as parameter to any function that may need it.

Example:

// I'd like to store it like that, but that isn't thread safe, other user may get the same token
export let globalToken : any;

export async function users(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {

   globalToken = validateToken(request);

   if(request.method === "GET"){
      return { jsonBody: getUsers() };
   }

}


//### In user.service.ts file ###

export const getUsers = () => {

   // so I can use it everywhere like that, without passing it in parameter every time
   return usersData.filter(u => u.userId === globalToken.userId)

}

Any suggestions?

3

There are 3 answers

2
Kristin On BEST ANSWER

I don't think what you're trying to achieve is doable without some sort of IoC that supports scoped lifecycles. Something like InversifyJS do support scoped lifecycles. I haven't used InversifyJS for Azure Functions before, though, and the samples I could find with my limited Google-foo skills seem experimental at best:

But the gist of it would be a service which is registered as scoped, and have a public property (either directly or via getter/setter methods) that can store your information (see inRequestScope for registering scoped services in InversifyJS).

Since the http trigger would be the root of the dependency graph in our case, and have the scoped service as dependency, any other dependencies we inject/resolve from our http trigger should share the same instance. Using the explanation on the about page for inRequestScope (the A -> B -> R, -> C -> R sample), "A" for us would be the HttpTrigger, and "R" would be the scoped service, "B" and/or "C" would be other services, like your user.service.ts.

I will note that this seems slightly excessive to implement, if all you want to achieve is to avoid having to parse values between methods (personal take). However, if your project is really large, and you have a lot of dependencies, and some of the values you have to parse around is for a dependency several layers deep, then I can understand why you want to avoid it.

1
Mohamed Azarudeen Z On

I guess you can use the context.bindingData object to store and retrieve data within the context of the current function invocation. let me give you a modified code.

export async function users(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
   const globalToken = validateToken(request);

   // u can store the token in the context.bindingData for the current invocation
   context.bindingData.globalToken = globalToken;

   if (request.method === "GET") {
      return { jsonBody: getUsers(context) };
   }
}

export const getUsers = (context: InvocationContext) => {
   // Retrieve the token from the context.bindingData
   const globalToken = context.bindingData.globalToken;

   // Use th token as wanted
   return usersData.filter(u => u.userId === globalToken.userId);
};

2
Fred On

Disclaimer: I don't think this is actually a good implementation from a security perspective. Storing a JWT is the same as storing a username/password. Better is to develop an impersonation scheme that allows all the functions invoked for a given JWT to impersonate a known identity related to some claim(s) in the JWT with the necessary permissions.

Use a key vault. Allow your initial function to store it there as a secret using correlation id as the key for uniqueness and not having to pass along to next function. In subsequent functions, that correlation id should be available in context. Use it to retrieve the token.

Related Questions in AZURE-FUNCTIONS-NODE.JS