/azure-quickstart/data-access/
Copy npm install jose
npm install openid-client
/azure-quickstart/data-access/shared-code/auth/msal.ts
Copy import { Issuer, Client } from 'openid-client';
import {JWT} from 'jose';
var verifyAccessToken = async (context) : Promise<[object, boolean]> => {
let token = context.request.headers["authorization"];
if (!token || !token.startsWith("Bearer ")) return [{}, false];
token = token.slice(7, token.length).trimLeft(); // Remove 'Bearer ' characters from start of Auth header value
const settings = {
audience: process.env.AAD_TOKEN_APPLICATION_ID,
openIdConfigUrl: process.env.AAD_TOKEN_OPEN_ID_CONNECT_METADATA_DOCUMENT,
tenantId: process.env.AAD_TOKEN_TENANT_ID
};
const issuer = await Issuer.discover(settings.openIdConfigUrl);
const keyStore = await issuer.keystore();
var results = JWT.verify(
token,
keyStore,
{
audience: settings.audience,
// issuer:
//issuer must remain commented out if you're accepting tokens from :
// Microsoft's public endpoint (which will be: 'https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0' or it can be any AAD tenant's ID)
//if you only want to accept local AAD Accounts use: `https://login.microsoftonline.com/${settings.tenantId}/v2.0`
}
);
return [
{
"authToken": results,
},
true
];
}
export default {
VerifyAccessToken: verifyAccessToken
}
Replace the contents of the main function file with the following to properly reference MSAL and to allow for auth headers.
/azure-quickstart/data-access/graphql/index.ts
Copy let appInsights = require("applicationinsights");
appInsights.setup().start();
appInsights.defaultClient.commonProperties = {
environment: process.env.WEBSITE_HOSTNAME,
functionArea: "graphql"
};
let appInsightsClient = appInsights.defaultClient;
import {
ApolloServerPlugin,
GraphQLRequestContext,
GraphQLRequestListener,
} from 'apollo-server-plugin-base';
import { ApolloServer, gql } from 'apollo-server-azure-functions';
import MsalAuth from '../shared/auth/msal';
import { HttpRequest, Context } from '@azure/functions';
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: (parent,args,context) => {
return `Hello world! ${JSON.stringify(context)}`
},
},
};
// referenced from https://jeffmagnusson.com/post/graphql-apollo-server-plugins-in-typescript
const appInsightsPlugin = <ApolloServerPlugin & GraphQLRequestListener>{
// Fires whenever a GraphQL request is received from a client.
requestDidStart(requestContext:GraphQLRequestContext): GraphQLRequestListener | void{
appInsightsClient.trackMetric({name: "apollo-query", value: 1});
return this;
},
// Fires for graph exceptions
didEncounterErrors: function(requestContext:GraphQLRequestContext) {
appInsightsClient.trackMetric({name: "apollo-error", value: 1});
appInsightsClient.trackException({exception: new Error("Apollo Error")});
appInsightsClient.trackException({exception: {category:"Apollo Error", details: requestContext.errors}});
}
}
const getPlaygroundSetting = () => {
if(process.env.APOLLO_PLAYGROUND_VISIBLE === "true" ){
if(process.env.APOLLO_PLAYGROUND_ENDPOINT){
return {endpoint :process.env.APOLLO_PLAYGROUND_ENDPOINT}
}
return true
} else {
return false
}
}
const server = new ApolloServer(
{
typeDefs,
resolvers,
playground: {endpoint:process.env.APOLLO_PLAYGROUND_ENDPOINT},
plugins: [
appInsightsPlugin
],
context: async (request) => {
var [ user, validated ] = await MsalAuth.VerifyAccessToken(request);
return {user, validated};
},
},
);
const graphqlHandler = server.createHandler({
cors: {
origin: '*',
credentials: true,
},
});
export default (context: Context, req: HttpRequest) => {
// https://github.com/Azure/azure-functions-host/issues/6013
req.headers['x-ms-privatelink-id'] = '';
// apollo-server only reads this specific string
req.headers['Access-Control-Request-Headers'] = req.headers['Access-Control-Request-Headers'] || req.headers['access-control-request-headers'];
return graphqlHandler(context, req);
}
/azure-quickstart/data-access/local.settings.json
Copy {
...
"Values": [
{
...
"AAD_TOKEN_OPEN_ID_CONNECT_METADATA_DOCUMENT" : "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
"AAD_TOKEN_APPLICATION_ID" : "<< AAD API APPPLICATION IDENTIFIER>>",
"AAD_TOKEN_TENANT_ID" : "<< AAD API TENANT ID>>",
"APOLLO_PLAYGROUND_URI" : "http://localhost:7071/api/graphql"
...
}
]
...
}
Repeat the same steps for the data-access-west function app.