API app service Functions JWT JWT Validation web apps

Azure App Service – Authorize custom JWT tokens from API clients

While I recommend in most cases using Azure AD as IDP, one of the most interesting questions have been: ”how to authorize non-Azure-AD JWT tokens for App service?” – Luckily for us Microsoft released a feature just for this a while back, a possibility to reference custom authentication provider for App Service – and this feature supports authorizing your own tokens.

Backround

If you want to know more about the background, I recommend reading the following MS article:

https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-provider-openid-connect

Configuration notes

  • Issuer must match that of defined in the metadata file
  • clientID must be included in audience value
  • The token has to be signed with the private key of the IDP (or client in this case)

In the picture above the client can create token with self defined claims, as long as the issuer and signature value match to that of the authentication conf

Deployment

  1. deploy your own public key as JWKS metadata to any suitable service (I used functions for this)
  • I used GitHub actions to create the JWT provider and RSA key pair, then publish them with the function
  • Private key is produced as artifact for testing
  • The solution is deployed into my honeypot 🙂
    • Ensure that you include X5C key type

2. In App Service Authentication reference the metadata

3. Once the deployment is done, I used the private key to create signed token, and then send it in authorization header to app service, which was configured with the authentication settings provided in metadata

References (code snippets)

  • Github actions for deployment
  • Node js with JSONwebtoken and axios libraries

GitHub deployment file

name: Node CI
on: [push]
permissions:
      id-token: write
      contents: read
jobs:
  create-JWKS:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: npm install, build, and test
        run: |
          npm install
          npm install pem-jwk --global
      - name: generate metadata 
        run: |
          node main.js
      - name: Archive jwks file
        uses: actions/upload-artifact@v2
        with:
          name: jwks
          path: |
            jwks
      - name: Create archive for the signin key
        uses: actions/upload-artifact@v2
        with:
          name: privateKey
          path: |
            private1.pem
  create-Server:
    runs-on: ubuntu-latest
    needs: create-JWKS
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Download JWKS file
        uses: actions/download-artifact@v2
        with:
          name: jwks
      - name: Setup JWKS server
        run: |
          cp jwks ./metadataserver/azapp/public/.well-known/
          cat metadataserver/azapp/public/.well-known/jwks
          cd metadataserver
          cd azapp
          npm install
          ls;ls
      - name: 7Z
        run: |
          cd metadataserver
          7z a -tzip deploy.zip . -r -mx0 -xr\!*.git -xr\!*.vscode 
          mv deploy.zip $GITHUB_WORKSPACE
      - name: Create archive for the Azure Functions Metadata server
        uses: actions/upload-artifact@v2
        with:
          name: deploy.zip
          path: |
            deploy.zip
            
  AZ-CLI-WORK:
    runs-on: ubuntu-latest
    needs: create-Server
    steps:
    - name: Checkout repository
      uses: actions/checkout@v2
    - name: 'Az CLI login'
      uses: azure/login@v1
      with:
          client-id: 50da2850-3ad2-409c-aafb-7bd76961f75a
          tenant-id: 033794f5-7c9d-4e98-923d-7b49114b7ac3
          subscription-id: 3539c2a2-cd25-48c6-b295-14e59334ef1c
    - name: Download JWKS file
      uses: actions/download-artifact@v2
      with:
        name: deploy.zip
        
    - name: Azure CLI script
      uses: azure/CLI@v1
      with:
        inlineScript: |
          chmod +x $GITHUB_WORKSPACE/sampleScript.sh
          $GITHUB_WORKSPACE/sampleScript.sh
          
          
         

Client-side Node code for issuing tokens with the Private key Artifact

const {createToken} = require('./src/getAADtokenWithCert')
const {getKey, jwtverify} = require('./src/helpers')
const { decode } = require('jsonwebtoken')
const { default: axios } = require('axios')
// Destructure config for reading Public and Private Key's
//
var priv = require('fs').readFileSync('./private1.pem').toString()
//Wrap into async function 
async function getToken() {
    var claims = {
        "aud": `1e73570f-5af0-4157-bec5-71783dfe6e64`,
        "iss": "https://fn-honeyPot-wellknown.azurewebsites.net",
        "sub": "1e73570f-5af0-4157-bec5-71783dfe6e64",
        "actor":"jose@securecloud.blog"
    }
var det =await getKey(`${claims.iss}/.well-known/jwks`)    
var {x5t, key} = det
     var jwt = await createToken(x5t,priv,claims).catch((error) => {
        return error
      }
    )
    var res =await jwtverify(jwt,key)
    console.log(res)
    console.log('')
    var opt = {
        url:"https://consumerappforjwt.azurewebsites.net/",
        method:"get",
        headers:{
            authorization: `Bearer ${jwt}`
        }
    }
    console.log('s')
    var data= await axios(opt
    ).catch((error) =>{
        console.log(error?.response)
    })
    console.log(data?.data)
    return jwt
}
getToken().then((token) => {
    console.log(token)
    console.log('Success:',decode(token,{complete:true}))
    
    
})

End

These are just snippets to give idea of the deployment workflow and usage. If there is interest I can create a public repo with the code.

0 comments on “Azure App Service – Authorize custom JWT tokens from API clients

Jätä kommentti