Skip to content

Commit 9104bfd

Browse files
committed
Proposed refactoring of API Plugin from Scratch with OAuth to separate middleware from app
1 parent 3b8dd69 commit 9104bfd

File tree

3 files changed

+32
-13
lines changed

3 files changed

+32
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,56 @@
11
import { HttpRequest } from "@azure/functions";
2-
import { TokenValidator } from "./tokenValidator";
2+
import { TokenValidator, EntraJwtPayload } from "./tokenValidator";
33
import config from "./config";
44
import { getEntraJwksUri, CloudType } from "./utils";
55

6+
// Export symbols app devs will need to use
7+
export { CloudType } from "./utils";
8+
export { EntraJwtPayload } from "./tokenValidator";
9+
610
/**
711
* Middleware function to handle authorization using JWT.
812
*
913
* @param {HttpRequest} req - The HTTP request.
10-
* @returns {Promise<boolean>} - A promise that resolves to a boolean value.
14+
* @returns {Promise<EntraJwtPayload | false>} - A promise that resolves to an array of JWT claims or false if authentication failed
1115
*/
12-
export async function authMiddleware(req?: HttpRequest): Promise<boolean> {
16+
export async function authMiddleware(req: HttpRequest,
17+
scope: string | [string],
18+
allowedTenants: [string] = [config.aadAppTenantId],
19+
cloud: CloudType = CloudType.Public,
20+
issuer: string = `https://login.microsoftonline.com/${config.aadAppTenantId}/v2.0`
21+
): Promise<EntraJwtPayload | false> {
22+
1323
// Get the token from the request headers
1424
const token = req.headers.get("authorization")?.split(" ")[1];
1525
if (!token) {
1626
return false;
1727
}
1828

1929
try {
20-
// Get the JWKS URL for the Microsoft Entra common tenant
21-
const entraJwksUri = await getEntraJwksUri(config.aadAppTenantId, CloudType.Public);
30+
// Get the JWKS URL for the specified Microsoft Entra cloud
31+
const entraJwksUri = await getEntraJwksUri(config.aadAppTenantId, cloud);
2232

2333
// Create a new token validator with the JWKS URL
2434
const validator = new TokenValidator({
2535
jwksUri: entraJwksUri,
2636
});
2737

2838
const options = {
29-
allowedTenants: [config.aadAppTenantId],
39+
allowedTenants: allowedTenants,
3040
audience: config.aadAppClientId,
31-
issuer: `https://login.microsoftonline.com/${config.aadAppTenantId}/v2.0`,
32-
scp: ["repairs_read"],
41+
issuer: issuer,
42+
scp: typeof scope === 'string' ? [scope] : scope
3343
};
3444
// Validate the token
35-
await validator.validateToken(token, options);
45+
const claims = await validator.validateToken(token, options);
46+
47+
return claims;
3648

37-
return true;
3849
} catch (err) {
50+
3951
// Handle JWT verification errors
4052
console.error("Token is invalid:", err);
4153
return false;
54+
4255
}
4356
}

templates/ts/api-plugin-from-scratch-oauth/src/functions/middleware/tokenValidator.ts

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export interface EntraJwtPayload extends JwtPayload {
2727
roles?: string[];
2828
scp?: string[];
2929
ver?: string;
30+
name?: string;
31+
oid?: string;
32+
preferred_username?: string;
33+
tid?: string;
3034
}
3135

3236
export class TokenValidator {

templates/ts/api-plugin-from-scratch-oauth/src/functions/repairs.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
77

88
import repairRecords from "../repairsData.json";
9-
import { authMiddleware } from "./middleware/authMiddleware";
9+
import { authMiddleware, EntraJwtPayload } from "./middleware/authMiddleware";
1010

1111
/**
1212
* This function handles the HTTP request and returns the repair information.
@@ -55,13 +55,15 @@ app.http("repairs", {
5555
authLevel: "anonymous",
5656
handler: async (req: HttpRequest, context: InvocationContext) => {
5757
// Check if the request is authenticated
58-
const isAuthenticated = await authMiddleware(req);
59-
if (!isAuthenticated) {
58+
const entraIdClaims = await authMiddleware(req, "repairs_read");
59+
if (!entraIdClaims) {
6060
return {
6161
status: 401,
6262
body: "Unauthorized",
6363
};
6464
}
65+
console.log(`Authenticated ${req.method} request for ${entraIdClaims.name} (${entraIdClaims.oid})`);
66+
6567
// Call the actual handler function
6668
return repairs(req, context);
6769
},

0 commit comments

Comments
 (0)