Skip to content
CAMPUX Cloud Bootcamp Phase Three · Class Twenty-Three
Phase Three — DevOps Core
4 drills · 2 situations · 2 Labs
Aligned to AZ-400
Class Twenty-Three

Actions → Azure with OIDC

A workflow needs permission to read or change Azure resources. Give it a short-lived identity for each run, tied to the repository and job that requested it, instead of storing a long-lived client secret.

Phase Three · DevOps Core · Class 23 of 42 · 21 min · Assumes Class 9 and Class 22

After this you can let a pipeline into Azure with OIDC federation and no stored secret.

New to this? Read Class 9 and Class 22 first. Already done them, or know the material? Carry on.

The hands-on part also needs permission to create an app registration and assign a role in your subscription.

§1

The old way, and why it should scare you

One way to connect GitHub Actions to Azure is to create an app registration and service principal, generate a client secret, and store that secret in GitHub. The secret is a reusable credential. If the app has broad Azure RBAC permissions, anyone who obtains the secret may use those permissions until the credential expires or is revoked. Scope the role narrowly either way.1

A stored secret needs protection, rotation, and eventual revocation. A workflow that can access it must be reviewed as privileged code; log masking is only a backstop. OIDC federation removes this long-lived client secret from GitHub. It does not remove the need to protect workflow changes, limit Azure roles, or avoid printing the short-lived tokens issued during a run.

OIDC federation
A trust relationship in Microsoft Entra ID that accepts a signed GitHub OIDC token with matching issuer, subject, and audience. The workflow exchanges that token for short-lived Azure access without a stored client secret.
§2

The handshake — tokens, trust, nothing stored

With OpenID Connect, the job requests a signed identity token from GitHub instead of reading a stored client secret. Entra checks that token against the trust you configured and may issue a short-lived Azure access token. The workflow still handles live tokens while it runs, so keep them out of logs. Follow the five steps:

1 · The run asks
The job requests an OIDC token from GitHub's identity provider — allowed because the workflow declares permissions: id-token: write.
2 · GitHub signs
GitHub mints a signed JWT describing the run: which repository, which branch or environment, which event. This is the subject claim — the run's identity papers.
3 · Entra checks
The token goes to Entra ID, which checks it against the federated credential on your app registration: right issuer, right subject, right audience. No match, no entry.
4 · Entra issues
On a match, Entra returns a short-lived access token for the service principal. The token remains usable until it expires, so the job must not disclose it.
5 · The job works
The azure/login action holds that token; every az command in the job runs with exactly the RBAC the principal was granted in Class Eight fashion.
Figure 1 — The OIDC handshake between GitHub, Entra ID, and Azure, with the stored-secret path struck through GitHub workflow run Proves who it is Entra ID federated credential Checks the papers Azure subscription Grants only its RBAC signed token access, minutes only scoped by RBAC reusable client secret stored in GitHub the old way — nothing travels this road anymore
Figure 1 — Three actors, one handshake, no stored key GitHub signs a statement about the run; Entra ID checks it against the federated credential and issues short-lived access subject to Azure RBAC. The dashed road shows the older stored-client-secret path.

The durable client secret is gone. Each authorized job requests fresh, short-lived tokens, while the federated credential records which GitHub subject Entra will trust. You can inspect and revoke that trust. A token accidentally exposed during a run can still be used until it expires, and a workflow that can request tokens still needs review.

§3

Federated credentials and the subject claim

The setup is three Azure-side objects and one workflow block. On the Azure side: an app registration (the Class Nine service principal), a federated credential attached to it, and an RBAC role assignment scoped as tightly as Class Eight taught. The federated credential is small enough to read in full:

# the trust object on the app registration
Issuer:   https://token.actions.githubusercontent.com
Subject:  repo:campux/campux-platform:environment:production
Audience: api://AzureADTokenExchange

The subject is one part of the authorization boundary. A branch subject such as repo:ORG/REPO:ref:refs/heads/main matches a job on main that does not declare an environment. An environment subject such as repo:ORG/REPO:environment:production matches jobs targeting that environment; it does not also prove they came from main. Restrict the environment to the intended deployment branches, configure reviewers where supported, and grant the Azure identity only the RBAC it needs. A broad repo:ORG/REPO:pull_request subject is unsuitable for production. The workflow requests a token with:

# deploy.yml (excerpt) — note what is absent: any secret value
permissions:
  id-token: write
  contents: read

steps:
  - uses: azure/login@v3
    with:
      client-id: ${{ secrets.AZURE_CLIENT_ID }}
      tenant-id: ${{ secrets.AZURE_TENANT_ID }}
      subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

The client, tenant, and subscription IDs identify the target; they do not authenticate on their own.2 The Azure Login action recommends storing them as GitHub secrets, as shown. This design removes a reusable client secret, but do not assume a leaked workflow log is harmless: a run can still hold short-lived tokens, and a malicious workflow with matching OIDC claims could request new ones.

Worked example · then predict

Three IDs and one subject, filled in

AZURE_CLIENT_ID        11111111-aaaa-4bbb-8ccc-000000000001   # the app registration's Application (client) ID
AZURE_TENANT_ID        22222222-aaaa-4bbb-8ccc-000000000002   # your Microsoft Entra directory
AZURE_SUBSCRIPTION_ID  33333333-aaaa-4bbb-8ccc-000000000003   # where its Reader role is assigned
Federated credential subject:  repo:campux/campux-platform:ref:refs/heads/main

The first three tell azure/login which identity, which directory and which subscription. None of them is a secret. The subject is the lock: only a token from a job on main in that repository fits it.

Predict: a teammate runs the same workflow from a branch called feature/logo. What does the login step do?

Check your prediction

It fails. Microsoft Entra ID compares the token's subject, repo:campux/campux-platform:ref:refs/heads/feature/logo, with the credential's subject and finds no match, so it refuses with an error naming the unmatched subject (code AADSTS700213). Nothing was leaked and nothing changed in Azure; that refusal is the design working. To allow the branch you would add a second credential, not widen the first.

Play

Play it through

Three minutes. Revoke the old client secret, configure Entra to trust one repository and branch, then test a pull request whose subject does not match. The game pauses for your choices.

§4

Environments and approvals — the human gate

OIDC answers how a job proves its identity. GitHub environment rules decide which jobs may target a named deployment environment. Where required reviewers are supported, configure them for production, and restrict deployment branches to main. A job declaring environment: production waits for those configured rules before it runs; its OIDC subject then names the environment. Entra matches that subject against the production federated credential. The environment name alone neither demands approval nor limits the branch.

No long-lived client secret in GitHub.

An environment subject does not include the branch by default. A feature-branch workflow that is allowed to target production can present the same environment subject after passing any configured rules. Use the environment's branch restrictions and approval rules together with a narrowly scoped Azure role. Protect workflow changes too: a trusted run with id-token: write can request a new OIDC token.

GitHub normally withholds repository secrets and limits the repository token on forked pull requests. Do not make that the only Azure control. A branch-scoped credential for main will not match a pull-request subject, regardless of whether the PR comes from a fork or the same repository. Be especially careful with pull_request_target: it runs in the base repository context, and checking out and executing untrusted PR code there can expose powerful credentials. Review the event, subject, environment rules, and Azure RBAC together.

Case File · Campux Retail

A production design to build toward

two jobs, two Azure identities, no stored client secret

Consider a future deploy.yml with separate non-production and production jobs. The non-production job runs from main without an environment and matches a branch-scoped federated credential. The production job names the protected production environment and matches a different environment-scoped credential. Each Azure identity receives permissions only on its own resource group. Required reviewers and a main-only deployment-branch rule must be configured on the production environment; the subject alone cannot enforce both. An authenticated what-if could be reviewed before deployment, but neither lab in this class implements a deploy.

The three Azure IDs may still appear in GitHub's Secrets list. What this design avoids storing is an Azure client secret. The reviewable evidence is the two trust configurations, the Azure role assignments, the environment rules, and the workflow diff. Short-lived tokens still deserve protection while a run is active.

Fig. 2 · Conceptual deploy workflow with separate Azure trusts
GitHub Actions deploy.yml · on merge no client secret two credentials on separate identities distinct subjects: repo:campux/campux-platform: ref:refs/heads/main or environment:production no client secret Azure nonprod auto on merge production review + main-only rule environment:production OIDC token short-lived token then, gated Azure client secret absent; review both trusts
This is a proposed design, not the Class 23 lab. The main-branch job and production-environment job present different OIDC subjects and use separate Azure identities. Production also needs a branch restriction and, where supported, a required reviewer. Both jobs avoid storing an Azure client secret.
§5

The Class Nine promise, kept

Step back and see the arc, because interviewers who probe this topic are really probing whether you see it. Class Nine drew the line: humans get accounts, machines get identities, and the best machine identity is one with no credential to manage — that was managed identity, and it worked only for things running inside Azure. A GitHub runner lives outside, so for five classes the question hung open: what about the machine that is not ours?

OIDC federation is the same idea stretched across an organisational boundary. Managed identity works because Azure vouches for its own compute; federation works because Entra is told, precisely and revocably, to accept GitHub's vouching for a specific repository, branch, or environment. Same principle — trade stored credentials for attested identity — new trust anchor. And the pattern is bigger than this class: the same federated-credential mechanism connects Kubernetes workloads, other clouds, and other CI systems to Entra without a stored key.3 When an interviewer asks "how does your pipeline authenticate?", the strong answer walks the Figure 1 handshake and then names the general rule. The weak answer says "we have a secret for that" — and now you know exactly what follows from it: an unrotated key, an unanswerable audit, and a door that was never really locked.

Read · official references

Check both sides of the trust

GitHub's concept page first, then Microsoft's setup walkthrough
Docs · Both sides of the handshake

GitHub Docs — Configuring OpenID Connect in Azure
docs.github.com/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-azure

GitHub Docs — About security hardening with OpenID Connect
docs.github.com/actions/concepts/security/openid-connect

Lab 1 · Federate & log in

Log into Azure without a stored client secret

~20 minutes · Azure CLI + a GitHub repository you own · rights to create an app registration

Create a small, read-only identity and use it from a GitHub workflow. This lab signs in and reads a resource group; it does not deploy. Use Bash in Azure Cloud Shell for the commands, and replace <OWNER> with the exact owner shown in your repository URL. You need permission to create app registrations in your directory and Owner or User Access Administrator on the subscription to assign the Reader role. A personal free account has both; a work or school account often does not.

  1. In Azure Cloud Shell (Bash), create a uniquely named lab resource group, an app registration, its service principal, and a Reader assignment scoped to that group. Keep the displayed IDs for cleanup:

    RG_NAME="rg-oidc-lab-${RANDOM}-${RANDOM}"
    RG_ID=$(az group create --name "$RG_NAME" --location eastus --query id -o tsv)
    APP_ID=$(az ad app create --display-name "campux-oidc-lab-$RG_NAME" --query appId -o tsv)
    SP_OBJECT_ID=$(az ad sp create --id "$APP_ID" --query id -o tsv)
    az role assignment create --assignee-object-id "$SP_OBJECT_ID" \
      --assignee-principal-type ServicePrincipal --role Reader --scope "$RG_ID"
    printf 'Resource group: %s\nApp ID: %s\n' "$RG_NAME" "$APP_ID"
    What to notice: the role applies to this lab resource group only. If the role command reports an authorization error, ask an Azure administrator for role-assignment permission; do not widen the scope. Entra replication can also delay a newly created service principal.
  2. Attach the federated credential — the trust object itself:

    OWNER="<your-github-name>"; REPO="campux-platform"
    SUB_PREFIX=$(curl -s "https://api.github.com/repos/$OWNER/$REPO/actions/oidc/customization/sub" \
      | sed -n 's/.*"sub_claim_prefix": *"\([^"]*\)".*/\1/p')
    echo "$SUB_PREFIX"   # e.g. repo:you@12345678/campux-platform@987654321
    az ad app federated-credential create --id "$APP_ID" --parameters "{
      \"name\": \"github-main\",
      \"issuer\": \"https://token.actions.githubusercontent.com\",
      \"subject\": \"$SUB_PREFIX:ref:refs/heads/main\",
      \"audiences\": [\"api://AzureADTokenExchange\"]
    }"
    Why look the prefix up: GitHub now writes the owner and repository into the subject with their numeric IDs, repo:you@12345678/campux-platform@987654321:ref:refs/heads/main, on new repositories and on many older ones. A subject typed by hand as repo:you/campux-platform:... no longer matches, and the login fails with AADSTS700213. Reading the prefix from GitHub gives the exact form your repository uses. For a private repository the lookup needs your sign-in: gh api repos/$OWNER/$REPO/actions/oidc/customization/sub --jq .sub_claim_prefix. We found this when running the lab in October 2026: the hand-typed subject was refused even on main. What to notice: replace <OWNER> before running the command. If using another repository, replace its name too. This subject matches only a job on main that does not declare an environment.
  3. In that GitHub repository, add three Actions secrets: AZURE_CLIENT_ID (the printed APP_ID), AZURE_TENANT_ID (az account show --query tenantId -o tsv), and AZURE_SUBSCRIPTION_ID (az account show --query id -o tsv). Add a plain Actions variable LAB_RG_NAME with the printed resource-group name.

    What to notice: these three IDs are not passwords. The signed OIDC token is what proves the job's identity. We follow Azure Login's recommendation to keep its ID inputs in Secrets; the resource-group name is ordinary configuration.
  4. Review and merge .github/workflows/oidc-login.yml to main, then run it from the Actions tab. The manual-run button appears when the workflow file is on the default branch:

    name: OIDC login test
    on: workflow_dispatch
    permissions:
      id-token: write
      contents: read
    jobs:
      login:
        runs-on: ubuntu-latest
        steps:
          - uses: azure/login@v3
            with:
              client-id: ${{ secrets.AZURE_CLIENT_ID }}
              tenant-id: ${{ secrets.AZURE_TENANT_ID }}
              subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          - name: Read the lab resource group
            env:
              LAB_RG_NAME: ${{ vars.LAB_RG_NAME }}
            run: az group show --name "$LAB_RG_NAME" --query properties.provisioningState
    On screen: the Azure Login step succeeds, then the group query reports "Succeeded". This proves the short-lived login and Reader permission; it does not deploy anything. Keep the lab resources for Lab 2.
Note · if the login step fails with AADSTS700213 or a subject mismatch, compare the run's branch and repo against the federated credential's subject character by character — the match is exact, and case matters. That error is the lock working; make the papers match the door.
Lab 2 · The human gate

Observe an environment gate safely

~10 minutes · continues Lab 1 · repository Settings access

Add a lab-only environment and a second federated credential. If your repository supports required reviewers, you can also observe the approval pause. The lab continues to read the same resource group and makes no production change.

  1. In the repository, create an environment named oidc-lab. Restrict deployment branches to main. If Required reviewers is available, add a reviewer with repository read access. For a solo lab, self-approval works only when Prevent self-review is off; if it is on, use a second reviewer. On GitHub Free, Pro, or Team private repositories, required reviewers may be unavailable.

    What to notice: the environment subject identifies the environment, not the branch. The branch restriction is a separate rule you must configure.
  2. Add a second federated credential on the Lab 1 app, trusting the environment instead of the branch:

    # replace SUBJECT_PREFIX with the $SUB_PREFIX you printed in Lab 1
    az ad app federated-credential create --id "$APP_ID" --parameters '{
      "name": "github-oidc-lab-env",
      "issuer": "https://token.actions.githubusercontent.com",
      "subject": "SUBJECT_PREFIX:environment:oidc-lab",
      "audiences": ["api://AzureADTokenExchange"]
    }'
    What to notice: the main-branch and oidc-lab environment jobs present different subjects. Use separate federated credentials for them, and keep the environment's main-only branch restriction in place.
  3. Add environment: oidc-lab directly under the job's runs-on: line. Review and merge that change to main, then run the workflow again.

    On screen: if Required reviewers is configured, the job waits for approval before running. Otherwise, it can start immediately. The environment subject matches the second credential rather than the main-branch credential.
  4. If the job waits, an eligible reviewer can select Review deployments and approve it. Confirm the read-only query succeeds. In the same Cloud Shell session, verify $RG_NAME and $APP_ID still hold the lab values. Then delete only the lab group, service principal, and app you created: az group delete --name "$RG_NAME" --yes, az ad sp delete --id "$APP_ID", and az ad app delete --id "$APP_ID". Remove the three lab IDs, the LAB_RG_NAME variable, and the practice workflow from GitHub after review.

    The lesson: configured GitHub environment rules govern when a job starts. The job's environment subject then determines which federated credential can authenticate it. Azure RBAC still determines what the job may read or change.
Think in systems

Zoom out: the best-held secret is the one that never exists

You can wire OIDC federation. Now reason about the whole system: it removes a reusable client secret, while workflow permissions, live tokens, environment rules, and Azure RBAC still need protection.

Feedback loops

A stored deploy secret must be rotated, so rotation is deferred, so it expires mid-deploy or leaks — and the "fix" is another stored secret. Federation ends the loop by storing nothing to rotate.

Dependencies & coupling

The pipeline’s access now depends on a federated trust between the identity provider and Azure, scoped to a subject — trust, not a copyable string that walks out on a laptop.

The constraint

Removing one stored secret reduces exposure, but a workflow that can mint short-lived Azure tokens remains privileged code.

Second-order effects

An environment subject alone does not bind a job to main. Without deployment-branch restrictions, a feature branch may request the same environment identity after passing its configured rules.

What breaks when it scales

One shared secret across pipelines means one leak rotates everyone; per-pipeline federated credentials contain the blast radius by design.

A useful review question is: which exact run may request each Azure identity, who may approve it, and what can that identity do?

On the job

No expiry to babysit, ever again

You · Cloud Engineer · a pipeline secret is expiring

A client secret used by CI is approaching expiry. The team first tests an OIDC login with a narrowly scoped Azure identity, then updates the deployment workflow, verifies its access, revokes the old Azure credential, and removes its GitHub copy. The Azure IDs may remain in the repository's Secrets list; the reusable client secret is gone.

Class Twenty-Three

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored; this is between you and the page.

Drill 01Recall · flow order
Put the OIDC handshake in order. Which sequence is correct?
Marked

B. GitHub issues a signed identity token to the job; Entra checks its claims against the federated credential and grants short-lived access subject to Azure RBAC. A incorrectly stores the access token as a GitHub secret. C confuses an optional human gate with authentication. D treats Entra as a workflow-code scanner, which it is not.

Drill 02Recall · trust
What, exactly, makes Entra ID accept a token from a GitHub workflow run?
Marked

C. The federated credential is a three-part filter sitting on the app registration: issuer (GitHub's token service and nobody else's), subject (this repo, this branch or environment), audience (the Azure exchange). All three match or the exchange is refused — there is no partial credit. A smuggles the stored secret back in, which is precisely what federation eliminates. B would be catastrophic if true; visibility has nothing to do with trust. D describes nothing that exists — the trust is an object in your tenant, created, audited, and deleted by you, which is why the auditor conversation in Situation 01 goes so well.

Drill 03Select three
Which three are genuine advantages of OIDC federation over a client secret stored in GitHub?
Marked

Nothing stored, short-lived tokens, subject-scoped trust. The two false options fail the same way: they credit authentication with jobs that belong elsewhere. RBAC is untouched by OIDC — federation changes how the principal proves itself, never what it may do, and the Class Eight role assignment matters exactly as much as before. And no authentication scheme reviews code; a perfectly federated pipeline will deploy a perfectly broken template with flawless credentials. Keep the layers separate — identity, authorization, quality — because the drill's wrong answers are, in the wild, the assumptions behind real incidents.

Drill 04Spot the error
This federated credential is for the principal that holds Contributor on Campux's production resource group. One line is a serious mistake. Which?
# federated credential — campux production deployer
1.  Name:     github-prod
2.  Issuer:   https://token.actions.githubusercontent.com
3.  Subject:  repo:campux/campux-platform:pull_request
4.  Audience: api://AzureADTokenExchange
5.  # principal role: Contributor on rg-campux-prod
Marked

Line three. The pull_request subject is far too broad for a production Contributor identity: it can match pull-request jobs from branches inside the repository. A workflow with permission to request an OIDC token could then ask Entra for production access before merge. Do not rely on ordinary fork restrictions to protect same-repository branches.

Use a production environment subject only together with the environment's main-only branch restriction and a required reviewer where supported. The environment subject itself does not contain the branch. The issuer identifies GitHub, the audience identifies the Azure token exchange, and the credential name is only a label. Review the workflow and the GitHub environment rules alongside this trust.

Situation 01Write before you reveal
An auditor reviewing Campux's release process asks the standard question: "Where are your deployment credentials stored, who can access them, and when were they last rotated?" Answer as the engineer who built the pipeline.
The honest answer to "where are they stored" is the whole story. Say it, then prove it.
Reasoning

State the exact boundary. The Azure client secret is not stored in GitHub. A permitted job receives a short-lived GitHub OIDC token and exchanges it for short-lived Azure access. The client, tenant, and subscription IDs may still be stored as GitHub secrets, but they are identifiers, not login credentials. The active tokens must still be protected until they expire. Instead of a rotation date for a client secret, show which runs may request tokens and how the federated trust can be revoked.

Then hand over evidence, not assurances. Auditors trade in artifacts. Show the federated credentials on the app registrations — issuer, subject, audience, readable in one screen. Show the RBAC assignments: non-prod's principal holds Contributor on its resource group, production's on its own, nothing subscription-wide. Show the production environment's required-reviewer rule and the deployment history of who approved what, when. Every claim you made in the first paragraph corresponds to an object they can inspect — which is the difference between a security posture and a security story.

Name the remaining risk. A malicious workflow change on a permitted branch can request tokens. An environment-scoped subject alone does not limit that job to main; show the environment branch restriction and approval configuration as separate evidence. Review .github/ changes and keep Azure RBAC narrow.

Situation 02Write before you reveal
A teammate setting up a new repository's pipeline says: "The OIDC setup is fiddly — app registrations, federated credentials, subjects that have to match exactly. A client secret is one paste and it works. We'll rotate it quarterly, I promise. Ship now, harden later?" What do you say?
They are right about the twenty minutes. Price the other side of the trade.
Reasoning

Concede the setup cost. A stored client secret may be faster to configure initially. Federation requires an app identity, an exact trust subject, Azure RBAC, and a reviewed workflow. In return, it removes a reusable client credential from GitHub. It still requires ongoing review of workflow permissions, environment rules, and role assignments.

Explain the operational tradeoff. A stored secret needs a rotation and revocation owner. GitHub's log masking does not make logging it safe. If the team must temporarily use one, scope its Azure role, set an expiry, and track the migration to federation. Do not present a calendar promise as the whole control.

Offer a concrete path. Reuse the reviewed login pattern from this class, replace the repository subject with the exact new owner and name, assign the new Azure identity only the needed role, and test a read-only command first. Estimate setup time from your team's own experience instead of promising it takes twenty minutes everywhere.

Examination record · first attempt
0/4
Class Twenty-Three · Complete
Retain this much

Five things worth carrying out of this class

  1. A stored Azure client secret is reusable until expiry or revocation. Keep Azure role assignments narrow whether you use that secret or OIDC.
  2. OIDC: the job requests a signed GitHub token; Entra checks issuer, subject, and audience; Azure access is then short-lived and governed by RBAC.
  3. A branch subject and an environment subject are different. The environment subject does not include the branch by default.
  4. Client, tenant, and subscription IDs are identifiers, not a password. This lab stores them as GitHub secrets following Azure Login guidance. Keep live tokens out of logs.
  5. For a production environment, configure deployment-branch restrictions and required reviewers where supported, then review the workflow and Azure role together.
Notes
  1. The client-secret pattern is not wrong in every universe — it predates federation, and you will inherit pipelines built on it. The professional move on encountering one is not scorn but a migration ticket: the switch to OIDC changes the login step and deletes a secret, and the rest of the pipeline never notices. Knowing the old way well enough to replace it gracefully is itself an employable skill. ↩
  2. "Grants no access" is a claim about authentication, not an invitation to publish these values: a tenant id or subscription id helps an attacker aim phishing or enumerate targets, which is exactly why GitHub's own docs and the azure/login action still file them as secrets rather than variables. The load-bearing claim is narrower and solid — none of the three values in the login block can be exchanged for access without a token whose issuer, subject, and audience match your federated credential. ↩
  3. Federation can also point at a user-assigned managed identity instead of an app registration — same issuer/subject/audience trust, one less object to manage, and increasingly the recommended default. The concepts in this class transfer unchanged; if your shop uses that variant, only the Azure-side noun is different. As ever with identity features, check current docs before an interview — this corner of Azure moves quickly. ↩
How this connects to Class Thirty-Nine

Here you learn the Azure login. Later, you will build the whole delivery path.

This class teaches one specific job: let a GitHub Actions workflow prove its identity to Microsoft Entra ID with OIDC, so Azure access uses short-lived credentials instead of a stored password.

Class Thirty-Nine brings the pieces together in one production workflow: what starts a run, how jobs build and test, how a build artifact moves between jobs, how a GitHub environment can protect deployment, and how the deploy job uses the OIDC login you learned here. You do not need to memorize a complete pipeline yet; carry forward the identity flow and the rule that Azure RBAC decides what the workflow may do.