0

I've created azure functions with CosmosDB binding. These functions are authorized - they expect to receive the user JWT bearer from the Authorization header.

How can I use the user info in my queries to get resources based on the authorization. For example, get all the items in the partition {user.oid}-todos?

nrofis
  • 8,975
  • 14
  • 58
  • 113

1 Answers1

0

This post offers a detailed description and even an example how to handle users and permissions in CosmosDB.

Alternatively, if you just want to get the oid from the received token and use this as the partition key, I'd go for an approach as shown here and then just create queries based on the value.

Setup (Nuget) for Azure Functions v3, .NET Core 3.1:

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.8" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.9" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.7" />
    [FunctionName("CosmosDBAccess")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            [CosmosDB(ConnectionStringSetting = "CosmosDBConnection")]DocumentClient client,
            ILogger log)
        {
            // Get oid from your token 
            var token = string.Empty;
            var hasToken = req.Headers.TryGetValue("Authorization", out var tokenHeader);
            if (hasToken)
            {
                // Assuming token is in header as "Bearer <token>"
                token = tokenHeader[0].Split(" ")[1];
            }
            var handler = new JwtSecurityTokenHandler();
            var tokenS = handler.ReadToken(token) as JwtSecurityToken;
            var jti = tokenS.Claims.First(claim => claim.Type == "oid").Value;

            // Create query
            var uri = UriFactory.CreateDocumentCollectionUri("db", "collection");
            using (var query = client.CreateDocumentQuery(uri, 
                new FeedOptions() { PartitionKey = new Microsoft.Azure.Documents.PartitionKey(jti) })
                .AsDocumentQuery())
            {
                while (query.HasMoreResults)
                {
                    // Get results
                    FeedResponse<Document> recordSet = await query.ExecuteNextAsync<Document>();
                }
            }

            // more stuff

This returns all documents where the partition key equals the oid from the authorized calling user.

// Edit: Here I've added a sample for JS. However, I don't have any clue how to get the oid from the token. If you manage to obtain it, I think this might work. Please excuse my "bad practice" when it comes to JS, I don't use that at all.

module.exports = async function (context, req) {
    
    const { CosmosClient } = require("@azure/cosmos");
    const endpoint = "<your-cosmosdb-connection>";
    const key = "<your-key>"
    const client = new CosmosClient({ endpoint, key });

    var results = []

    async function main() {
        // Get oid
        var oid = req.headers.authorization.split(" ")[1]
        console.log(oid)

        // Get Database 
        const { database } = await client.databases.createIfNotExists({ id: "db" });
        console.log(database.id);
        
        // Get Collection
        const { container } = await database.containers.createIfNotExists({ id: "collection" });
        console.log(container.id);

        // Query items
        const { resources } = await container.items
            .query("SELECT * from c", { partitionKey: oid })
            .fetchAll();
        
        for (var r of resources)
        {
            results.push(r)
            console.log(r.id)
        }
    }

    main().catch((error) => {
        console.error(error);
    });

    await main()

    // Return response
    context.res = {
        // status: 200, /* Defaults to 200 */
        body: results
    };
}
DSpirit
  • 2,062
  • 16
  • 22
  • Ho, I'm sorry that I didn't mentioned earlier. I need it in JavaScript / TypeScript – nrofis Oct 06 '20 at 17:47
  • There are no such annotations in JavaScript / TypeScript. What is the alternatives in these platforms? – nrofis Oct 06 '20 at 18:07
  • 1
    At first you should get the CosmosClient: https://learn.microsoft.com/en-us/javascript/api/overview/azure/cosmos-readme?view=azure-node-latest#install-this-package Unfortunately neither I know how to get the _oid_ in js nor how to add the partitionkey feed option. Maybe you can find something in the docs: General: https://learn.microsoft.com/en-us/javascript/api/overview/azure/cosmos-readme?view=azure-node-latest Partition key: https://learn.microsoft.com/en-us/javascript/api/@azure/cosmos/partitionkey?view=azure-node-latest – DSpirit Oct 06 '20 at 18:56
  • @nrofis I've added a sample to my answer above. As mentioned, I don't know how to obtain the oid from a Bearer token. – DSpirit Oct 06 '20 at 21:03
  • 1
    Thanks! I have the code that get the `oid`. Actually, if Azure Functions will support this as part of the binding mechanism it will be awesome! Even though this code works, binding is much shorter and simpler. Thank you! – nrofis Oct 06 '20 at 21:15
  • Glad to hear that! If you have the _oid_ already, you might use the real js binding: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2-input?tabs=javascript#queue-trigger-get-multiple-docs-using-sqlquery-1 where you can also use the `partitionKey` property in the function.json and access the results via: `var documents = context.bindings.documents;` – DSpirit Oct 06 '20 at 21:24
  • I mean, I extract the oid from the Authorization header. It requires few basic JS commands, so I don't know if I can use the binding directly – nrofis Oct 06 '20 at 21:29