You’re two weeks into your first job. You run gh auth login, paste a token, and everything works. Then someone mentions “SAML SSO” in a Slack thread and you nod along. Then a curl request fails with 403 Forbidden and the error says something about “bearer token.” Then you overhear two staff engineers arguing about “OAuth vs OIDC” like it’s a religious war.
You have no idea what any of this means. You’re not sure which parts are protocols, which parts are products, and which parts are just acronyms people throw around to sound smart.
This post is the orientation guide I wish someone had handed me. Not a textbook chapter. Not a security course. Just a map of the territory, so when you bump into these terms in the wild, you know which drawer they belong in.
The two questions
All of auth boils down to two questions:
- Authentication (authn): Who are you?
- Authorization (authz): What are you allowed to do?
That’s it. Every protocol, every token, every login flow is answering one or both of these questions. The confusion starts because people say “auth” and mean either one, or both, or sometimes neither (they just mean “the login thing”).
Authentication is showing your driver’s license at the door. Authorization is the bouncer checking if your name is on the VIP list. Different questions, different systems, often handled by different software. But they get tangled together because in practice, you usually need to answer both before anything useful happens.
Keep this distinction loaded in your head. It’ll save you a lot of confusion.
The mental map
Here’s the thing about auth: there are maybe 15-20 terms that matter, and they live at completely different layers. Mixing up the layers is where confusion breeds. So before we dive into any single concept, here’s the taxonomy:
| Layer | What it answers | Examples |
|---|---|---|
| Identity Providers | Who stores “who you are” | Azure AD / Entra ID, Okta, Google Workspace |
| Protocols | How systems talk about identity | SAML, OAuth 2.0, OIDC, Kerberos |
| Token Formats | The actual artifact being passed around | JWT, opaque tokens, cookies |
| Credential Types | What humans/machines use to prove identity | Passwords, PATs, SSH keys, certificates |
| Access Control Models | Who can do what, structurally | RBAC, ABAC, ACLs |
| Patterns | How auth flows work in practice | SSO, MFA, federation, zero trust |
When someone says “we use OAuth with JWTs for SSO through Okta,” they’re touching four different layers in one sentence. That sentence is not insane. It just sounds insane if you don’t know which word belongs to which layer.
Let’s walk through each layer.
Identity Providers: who keeps the guest list
An Identity Provider (IdP) is the system that stores and manages user identities. It’s the source of truth for “this person exists, and here’s how to verify them.”
When your company says “log in with your corporate account,” they’re sending you to an IdP.
Azure AD / Entra ID
Microsoft’s IdP. If you work at a company that uses Microsoft 365, your corporate identity lives here. Microsoft recently renamed Azure Active Directory to “Entra ID” because apparently the branding team needed something to do. You’ll see both names in the wild. They’re the same thing.
Where you’ll see it: Every time you log into Teams, Outlook, or Azure portal. When GitHub Enterprise requires your corporate login, it’s probably redirecting to Entra ID behind the scenes.
Okta
A popular third-party IdP. Lots of companies use Okta to manage employee identities instead of (or alongside) Microsoft’s offering.
Where you’ll see it: That “Log in with Okta” button on internal tools. The Okta dashboard where all your company apps are tiles you can click.
Google Workspace
Google’s IdP for organizations. If your company uses Gmail and Google Docs for work, Google Workspace is your IdP.
Where you’ll see it: “Sign in with Google” on third-party apps. The fact that logging into Gmail also logs you into Google Cloud Console.
The pattern
All IdPs do the same fundamental thing: store identities, verify credentials, and issue some kind of proof that says “yes, this person is who they claim to be.” The differences are in the protocols they support, the ecosystems they integrate with, and which enterprise sales team got to your CTO first.
Protocols: how systems negotiate identity
A protocol is a set of rules for how two systems talk to each other about identity. The IdP knows who you are, but the app you’re trying to use needs to hear it from the IdP in a structured, trustworthy way. Protocols define that conversation.
SAML (Security Assertion Markup Language)
SAML is the elder statesman of enterprise SSO. It’s XML-based (yes, XML), designed in the early 2000s, and still everywhere in corporate environments.
The flow works like this: you try to access an app, the app says “I don’t know you, go talk to the IdP,” your browser redirects to the IdP’s login page, you authenticate there, and the IdP sends the app an XML document (called a “SAML assertion”) that says “this person is legit.” The app trusts the IdP because they exchanged certificates ahead of time.
Where you’ll see it: Enterprise SSO. When you click a link to an internal tool and get redirected to a corporate login page before you can see anything. GitHub Enterprise’s SAML SSO enforcement is a classic example.
Key trait: SAML is browser-based. The assertion travels through your browser via HTTP redirects and form posts. This matters more than you think. (We’ll come back to this.)
OAuth 2.0
OAuth 2.0 is an authorization framework. Note: authorization, not authentication. This is the single most common source of confusion in all of auth.
OAuth answers the question: “Can this app do things on my behalf?” Not “who is this person?” but “does this app have permission to read this person’s calendar?”
The classic example: you use a third-party app that wants to post to your Twitter account. You don’t give it your Twitter password. Instead, Twitter shows you a consent screen (“This app wants to: post tweets on your behalf”), you click “Allow,” and Twitter gives the app a token that lets it post tweets. The app never sees your password. It just gets a scoped permission slip.
Where you’ll see it: “Sign in with GitHub” buttons (though that’s technically using OAuth for authentication, which is… a whole thing). API integrations where one service accesses another on your behalf. GitHub Apps requesting repository permissions.
Key trait: OAuth is about delegated access. It’s the protocol that lets you give an app a key to one room in your house without giving it the master key.
OIDC (OpenID Connect)
OIDC is OAuth 2.0 with an identity layer bolted on top. Where OAuth says “this app can act on your behalf,” OIDC adds “and by the way, here’s who ‘you’ actually are.”
OIDC was basically the industry saying “everyone is using OAuth for authentication even though it wasn’t designed for that, so let’s standardize a way to do it properly.” It adds a standardized identity token (an id_token, which is a JWT) to the OAuth flow.
Where you’ll see it: Modern “Sign in with Google/Microsoft/GitHub” flows. When your CI system authenticates to cloud providers using workload identity federation. When you see id_token in a response alongside access_token.
Key trait: OIDC = OAuth + identity. If OAuth is a permission slip, OIDC is a permission slip that also includes a photo ID.
Kerberos
Kerberos is an authentication protocol used heavily in on-premise Windows/Active Directory environments. Named after the three-headed dog guarding the underworld, which is either very cool or very nerdy depending on your tolerance for classical mythology in network protocols.
It works with “tickets” rather than passwords. You authenticate once, get a ticket-granting ticket (TGT), and then use that to get service tickets for specific resources. All without sending your password over the network again.
Where you’ll see it: Corporate Windows environments. When you log into your work laptop and can magically access file shares and printers without re-entering your password. Less common in modern cloud-native setups, but still lurking in enterprise environments.
Key trait: Designed for trusted networks (like a corporate LAN). Doesn’t translate well to the internet, which is part of why SAML and OIDC took over for web-based SSO.
Token formats: the actual thing being passed around
Protocols define the conversation. Tokens are the physical artifacts that get exchanged during that conversation. Think of the protocol as the postal system rules, and the token as the actual letter being mailed.
JWT (JSON Web Token)
A JWT (pronounced “jot”) is a specific token format. It’s a base64-encoded JSON object with three parts separated by dots: header, payload, and signature.
eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.SflKxwRJSMeKKF2QT4fw...
That gobbledygook is just JSON that’s been base64-encoded. The header says what algorithm was used to sign it. The payload contains claims (key-value pairs like "sub": "user123", "exp": 1717000000). The signature proves it hasn’t been tampered with.
The crucial property of JWTs: they’re self-contained. Any service that has the public key can verify a JWT without calling back to the IdP. This is what makes them useful for distributed systems. The API server doesn’t need to phone home every time it sees a token.
The crucial footgun of JWTs: they can’t be revoked easily. Since verification is local, there’s no central authority to say “actually, ignore that token.” You have to wait for it to expire, or build a revocation list, which partially defeats the purpose of having self-contained tokens.
Where you’ll see it: OIDC id_tokens are JWTs. Many OAuth access_tokens are JWTs (though the spec doesn’t require it). If you base64-decode a token and see JSON with "exp", "iat", "sub" fields, you’re holding a JWT.
Key trait: JWT is a format, not a protocol. Saying “we use JWT for auth” is like saying “we use envelopes for mail.” True, but it doesn’t tell you much about the postal system.
Opaque tokens
An opaque token is just a random string. ghp_ABC123DEF456... tells you nothing about who it belongs to or what it can do. To validate it, you have to send it to the server that issued it and ask “is this still good?”
Where you’ll see it: GitHub Personal Access Tokens. Many API keys. Session IDs in cookies.
Key trait: The opposite of JWTs. Opaque tokens require a round-trip to validate but are easy to revoke (just delete them from the database).
Cookies
Cookies aren’t really a token format in the same sense. They’re a transport mechanism. Your browser automatically attaches cookies to every request to the domain that set them. The cookie might contain a session ID (opaque token), a JWT, or just a flag that says “this browser has authenticated.”
Where you’ll see it: Every website login ever. When you log into GitHub in your browser, a cookie keeps you logged in. When that cookie expires, you get redirected to login again.
Key trait: Browser-specific. APIs don’t use cookies (usually). This is part of why browser auth and API auth work differently.
Credential types: how you prove you’re you
Tokens are what systems exchange with each other. Credentials are what you (a human or a machine) present to get those tokens.
Passwords
You know what passwords are. The relevant thing for this map: passwords are almost never used directly with APIs. They’re used to authenticate to an IdP, which then issues a token. The token is what travels around the system. Sending raw passwords over APIs is a security smell.
Personal Access Tokens (PATs)
A PAT is a long-lived credential you generate manually and use in place of a password for API access. You go to a settings page, click “Generate token,” select some scopes (permissions), and get back a string you can use in API calls.
Where you’ll see it: gh auth login with a token. Git over HTTPS when your company has disabled password auth. CI pipelines that need to call APIs. The GITHUB_TOKEN in your workflow files.
Key trait: PATs are bearer credentials, meaning anyone who has the string can use it. No additional verification. If it leaks, whoever finds it can do whatever the token’s scopes allow. This is why PATs should have expiration dates and minimal scopes.
SSH keys
An asymmetric key pair (public + private) used for authentication. You give the server your public key, keep the private key on your machine, and prove your identity by signing a challenge with the private key.
Where you’ll see it: git clone git@github.com:.... SSHing into servers. The .ssh/authorized_keys file.
Key trait: More secure than PATs for interactive use because the private key never leaves your machine. But harder to scope (an SSH key typically gives you access to everything your account can do, not just specific repos or operations).
Certificates
Certificates are like SSH keys with metadata. They contain a public key, information about the holder, an expiration date, and a signature from a trusted authority (a Certificate Authority, or CA). TLS/HTTPS is built on certificates.
Where you’ll see it: The padlock icon in your browser. Mutual TLS (mTLS) in service-to-service communication. Some enterprise environments issue client certificates to machines.
Key trait: Certificates carry trust information. Instead of “I trust this specific key,” the model is “I trust this CA, and this CA vouches for this key.”
OIDC tokens (workload identity)
In modern cloud environments, machines can authenticate using short-lived OIDC tokens instead of stored secrets. The machine’s environment (a GitHub Actions runner, a Kubernetes pod) can request a token from an identity provider, and that token proves “I am this specific workload running in this specific environment.”
Where you’ll see it: GitHub Actions’ id-token: write permission for deploying to Azure/AWS without storing credentials. Kubernetes service accounts using workload identity federation.
Key trait: No stored secrets. The credential is ephemeral and tied to the execution context. This is the direction the industry is moving because it eliminates the “what if the secret leaks” problem entirely.
Access control models: who can do what
Once you know who someone is (authentication), you need to decide what they can do (authorization). Access control models are the frameworks for making that decision.
RBAC (Role-Based Access Control)
Assign roles to users, assign permissions to roles. A user gets all permissions from all their roles.
User "Zoe" → Role "DevEx Engineer" → Permissions: [read repos, write CI configs, push images]
User "Zoe" → Role "On-Call" → Permissions: [restart services, view logs, page team]
Where you’ll see it: Kubernetes RBAC (ClusterRole, RoleBinding). Azure RBAC (Reader, Contributor, Owner). GitHub’s repository permission levels (read, triage, write, maintain, admin). Basically every enterprise system built after 2005.
Key trait: Simple, widely understood, scales reasonably well. The downside is role explosion: as you add more fine-grained permissions, you end up with hundreds of roles and nobody remembers what each one does.
ABAC (Attribute-Based Access Control)
Instead of roles, permissions are determined by attributes of the user, the resource, and the environment. “Allow if user.department == ’engineering’ AND resource.sensitivity == ’low’ AND time.hour is between 9 and 17.”
Where you’ll see it: AWS IAM policy conditions. Sophisticated enterprise policy engines. Less common in day-to-day development, more common in compliance-heavy environments.
Key trait: More flexible than RBAC, but harder to reason about. Debugging “why can’t I access this?” becomes an exercise in evaluating boolean expressions across multiple attribute sources.
ACLs (Access Control Lists)
The simplest model: a list attached to each resource saying who can do what. File permissions in Unix (rwxr-xr-x) are ACLs. “This file is readable by owner and group, executable by everyone.”
Where you’ll see it: File system permissions. Network ACLs (firewall rules). Google Drive sharing settings (“Anyone with the link can view”).
Key trait: Straightforward for simple cases, becomes unmanageable at scale. If you have 10,000 files and 500 users, maintaining individual ACLs is a nightmare. That’s why RBAC exists.
Patterns: how auth flows work in practice
These aren’t protocols or technologies. They’re patterns, ways of combining the pieces above to solve common problems.
SSO (Single Sign-On)
Log in once, access many applications. Instead of having a separate username and password for every internal tool, you authenticate once with your IdP and all the connected apps trust that authentication.
Where you’ll see it: Logging into your corporate Okta dashboard and then clicking through to Jira, Confluence, GitHub, AWS Console, etc., without logging in again. The “Sign in with Google” button that lets you into dozens of unrelated services.
How it connects: SSO is the pattern. SAML and OIDC are the protocols that implement it. The IdP is the system that makes it work. When someone says “we have SAML SSO,” they mean “we use the SAML protocol to achieve single sign-on, backed by our IdP.”
MFA / 2FA (Multi-Factor Authentication)
Require more than one form of proof. Something you know (password) plus something you have (phone, hardware key) or something you are (fingerprint).
Where you’ll see it: The authenticator app on your phone. YubiKeys. The SMS code you get when logging into your bank. GitHub’s requirement to enable 2FA.
How it connects: MFA is an add-on to any authentication flow. Your IdP handles MFA during the authentication step, and the downstream apps don’t need to know or care how many factors were used.
Federation
Trust relationships between different identity systems. Organization A trusts Organization B’s IdP, so users from B can access A’s resources without creating new accounts.
Where you’ll see it: A contractor using their own company’s credentials to access your Azure resources. Cross-tenant collaboration in Microsoft 365. The fact that you can “Sign in with GitHub” on a website that has nothing to do with GitHub.
How it connects: Federation is built on top of protocols (SAML, OIDC). The protocol provides the technical mechanism for one system to verify identity claims from another.
Zero Trust
The philosophy that no network location is inherently trusted. Being “inside the corporate network” doesn’t mean you get to skip authentication and authorization. Every request must prove identity and permissions, regardless of where it comes from.
Where you’ll see it: The reason you still need to authenticate to internal services even when connected to the VPN. Modern security architectures that treat the corporate network the same as the public internet.
How it connects: Zero trust isn’t a protocol or product. It’s a design principle that affects how all the other pieces get deployed. It means more auth checks, more token validation, more granular permissions, everywhere.
The GitHub SAML SSO example: theory meets reality
Let’s ground all of this in something concrete.
You have a GitHub PAT. You’re trying to access a repository that belongs to an organization with SAML SSO enforcement enabled. Here’s what happens through two different doors:
Door 1: The browser (github.com)
You navigate to github.com/your-org/some-repo. GitHub sees you’re trying to access an SSO-protected org. Your browser gets redirected to the company’s IdP (let’s say Entra ID). You authenticate there (maybe with MFA). The IdP sends a SAML assertion back to GitHub. GitHub checks the assertion, confirms you’re a member of the org, and lets you in.
This is the full SAML SSO flow. Browser redirects, XML assertions, cookies being set. The whole ceremony.
Door 2: The API (api.github.com)
You run:
curl -H "Authorization: Bearer ghp_yourtoken..." https://api.github.com/repos/your-org/some-repo
No redirect. No SAML. No browser. The API checks your token directly. If the token has been authorized for SSO with that org (you did this once in your GitHub settings), the API lets you through.
Same person, different flow. Why?
Because SAML is browser-based. The SAML protocol relies on HTTP redirects and form posts that only make sense in a browser. An API client like curl can’t follow a redirect to a login page, enter a password, handle MFA, and POST a SAML assertion back.
So GitHub has two authentication paths:
- Web UI: Full SAML flow via browser redirects. The IdP is in the loop for every session.
- API: Token-based. The token was pre-authorized for SSO. The API trusts the token directly.
Same token, same user, different doors. The web door forces you through the SAML ceremony because it can (you have a browser). The API door trusts the token because it must (you don’t have a browser).
This is a pattern you’ll see everywhere in enterprise software: browser flows use redirect-based protocols (SAML, OIDC), API flows use token-based authentication (PATs, OAuth tokens). They coexist because they serve different clients.
What’s happening in auth terms
Let’s label the layers from our mental map:
| Component | Layer | What it is |
|---|---|---|
| Entra ID | Identity Provider | Stores your corporate identity |
| SAML | Protocol | Browser-based SSO flow |
| SAML assertion | Token | XML proof of authentication |
| GitHub PAT | Credential | Pre-shared token for API access |
| “authorized for SSO” | Access Control | PAT has been linked to the org’s SSO |
| Browser cookie | Token (transport) | Keeps the web session alive after SAML |
| Bearer header | Transport | How the API receives the token |
Every piece fits into a layer. None of them are magic.
Common confusions
These are the things that trip up even experienced engineers, usually because the names are misleading or the distinctions are subtle.
“OAuth is for authentication”
No. OAuth is an authorization framework. It’s about delegating access (“this app can read my repos”), not proving identity (“this person is Zoe”). The fact that everyone uses OAuth for “Sign in with X” doesn’t make it an authentication protocol. It makes it a widely misused authorization protocol, which is exactly why OIDC was invented.
“OIDC and SAML are competitors”
Sort of. They both solve SSO, but they come from different eras and have different design philosophies. SAML is XML-based, designed for enterprise browser SSO, and predates the modern web API ecosystem. OIDC is JSON-based, built on top of OAuth 2.0, and designed for both browser and API use cases. In practice, large enterprises often support both because some apps only speak SAML and some only speak OIDC.
“JWT is a protocol”
JWT is a token format. It tells you how the token is structured (header.payload.signature), not how it’s obtained or validated in the context of a larger system. OIDC is a protocol that uses JWTs. OAuth can use JWTs. You can also use JWTs for completely non-auth purposes, like passing claims between microservices.
“Bearer token” describes what a token is
“Bearer” describes how a token is sent, not what it is. A bearer token is any token where possession equals authorization. If you have it, you can use it. The Authorization: Bearer <token> header is just the HTTP convention for presenting one. The token itself might be a JWT, an opaque string, or anything else. “Bearer” tells you nothing about the format, only about the security model: whoever bears it gets access.
PAT vs OAuth token vs OIDC token
These are different things that can look similar:
| Token | Created by | Lifetime | Purpose |
|---|---|---|---|
| PAT | User, manually | Long-lived (days to years) | Human-to-API access |
| OAuth access token | OAuth flow | Short-lived (minutes to hours) | App-to-API delegated access |
| OIDC id_token | OIDC flow | Short-lived | Proof of identity (who you are) |
A PAT is something you create and manage yourself. An OAuth token is issued by an authorization server during a specific flow. An OIDC id_token is specifically about identity, not access. They’re different tools for different jobs, even though they all end up in an Authorization header.
“API key” and “PAT” are the same thing
Close, but not quite. An API key typically identifies an application (or project), while a PAT identifies a user. When you put an API key in your request, the server knows which app is calling but may not know which human. When you use a PAT, the server knows which human (or machine identity) is acting. Some services blur this distinction, but the conceptual difference matters for auditing and access control.
Cheat sheet
Pin this to a wall. Or don’t, because it’s 2026 and you can just search your browser history.
| Term | What it is | Layer | When you’ll see it |
|---|---|---|---|
| IdP | System that stores and verifies identities | Identity Provider | “Log in with your corporate account” |
| Entra ID (Azure AD) | Microsoft’s IdP | Identity Provider | Microsoft 365, Azure portal, Teams |
| Okta | Third-party IdP | Identity Provider | That tile dashboard with all your work apps |
| SAML | XML-based SSO protocol (browser) | Protocol | Corporate login redirects |
| OAuth 2.0 | Authorization delegation framework | Protocol | “This app wants to access your…” consent screens |
| OIDC | OAuth + identity layer | Protocol | “Sign in with Google/GitHub/Microsoft” |
| Kerberos | Ticket-based auth for trusted networks | Protocol | Windows domain environments |
| JWT | Self-contained JSON token (header.payload.sig) | Token Format | Base64 blobs with dots in them |
| Opaque token | Random string, server-validated | Token Format | PATs, session IDs |
| Cookie | Browser-managed credential transport | Token Transport | Every website login |
| Password | Something you know | Credential | Please don’t use these for APIs |
| PAT | Long-lived token you generate manually | Credential | gh auth login, CI pipelines |
| SSH key | Asymmetric key pair | Credential | git clone git@..., server access |
| Certificate | Key + metadata + CA signature | Credential | HTTPS, mTLS, enterprise machines |
| OIDC token | Short-lived workload identity | Credential | CI/CD deploying to cloud without secrets |
| RBAC | Roles → permissions | Access Control | Kubernetes, Azure, GitHub repo permissions |
| ABAC | Attributes → permissions | Access Control | AWS IAM conditions, policy engines |
| ACL | Per-resource permission list | Access Control | File permissions, firewall rules |
| SSO | Log in once, access many apps | Pattern | Corporate app dashboards |
| MFA/2FA | Multiple proof factors | Pattern | Authenticator apps, hardware keys |
| Federation | Cross-org trust | Pattern | Using your company creds on a partner’s system |
| Zero Trust | Never trust, always verify | Pattern | Auth checks even on internal networks |
| Bearer | Token possession = access | Transport | Authorization: Bearer <token> header |
How to read an auth error
When you hit an auth error in the wild, here’s the triage checklist:
- What’s the HTTP status?
401= authentication failed (who are you?).403= authorization failed (you’re not allowed). - What credential did you send? Check the
Authorizationheader or cookie. Is it present? Expired? Wrong type? - What’s the auth mechanism? Is the server expecting a bearer token, an API key, a cookie, basic auth?
- Is this a browser flow vs API flow? A
302redirect to a login page means the server wants browser-based auth. If you’re usingcurl, you need a different approach (token, API key). - Check scopes/permissions. Your token might be valid but lack the right permissions. A GitHub PAT without
reposcope can’t access private repos.
Most auth errors come down to: wrong credential type, expired credential, missing scope, or trying to use a browser flow from an API client. Start there.
The 30-second version
Auth answers two questions: who are you (authentication) and what can you do (authorization). Identity providers store identities. Protocols define how systems negotiate identity (SAML for browser SSO, OAuth for delegated access, OIDC for OAuth + identity). Tokens are the artifacts that get passed around (JWTs are self-contained, opaque tokens require server validation). Credentials are what you present to get tokens (passwords, PATs, SSH keys). Access control models determine permissions (RBAC uses roles, ABAC uses attributes, ACLs use per-resource lists). Patterns like SSO, MFA, and federation combine these pieces into real-world solutions.
Everything connects. Nothing exists in isolation. When you’re confused, figure out which layer the confusing term belongs to, and the rest usually falls into place.