OAuth — orientation and terms
This is a “primer” page for existing developers, to help orientate you when reading up about OAuth solutions.
You might notice that on this page (and the example pages), I’m trying to avoid some of the key terms set out in OAuth / OIDC. The reason for this, is to try and make OAuth more understandable in practice — this isn’t going to work for everyone, many developers will dive into the RFCs and pull out what then need straight away.
Common concepts to OAuth and OIDC
First I will cover off some of the “safe” terms and concepts that I prefer. I’m using the word “safe” here because these terms are unambiguous (not re-used) in different parts of the standards.
Flow
OIDC uses the term “Flow” more actively than OAuth. It describes the main use case / context, and it is important to understand how the choice of “flow” has massive impacts your real world implementation. In OAuth it uses the term “Grant” to distinguish between use cases, but confusingly the grant_type parameter is only used on the Token endpoint, and you start the sequence of events with a response_type parameter on the Authorize endpoint…
So, out of all the myriad of options, it comes down to two flows for me:
- Authorisation code flow
- Client credentials flow
(Although I am not the only one struggling to decide on a term — OAuth 2.0 has an extension for the Device Authorization Grant (RFC8628), which was originally “Device Flow”)
Legs
The term “legs” isn’t used enough! It tells you how many parties are involved in the journey. Two types:
- Two legged — just a client and server
- Three legged
Three legged involves a third server or endpoint — and provides a back-channel between the OAuth Server and your infrastructure. It should make any implementation impossible to break into:
- That endpoint is pre-shared during configuration, so can’t be changed by the client
- The endpoint has to exist and respond correctly to complete the user journey
The “flow” name doesn’t provide any hint of whether it is two or three legged, yet is has the largest implementation impact.
(I used the term “…should make any implementation impossible…”, this is security, never assume something is impossible!)
Redirects are your friend
The isolation between parties and the elegance of the standard is all around the re-directs:
- each leg of the journey manages a specific functional part
- for instance, if you call out to an OIDC provider for authentication, it can add in multi-factor authentication without a change in your software
- as one part completes, it hands control over to the next part
- finally control is returned to the browser, normally to the place the user started at prior to asking to login.
Tokens
This term is used nice and consistently, although the “claims” inside of the tokens can get a bit tangled up. Types of token are:
- Access Token — the token to indicate successful authorisation (implied authentication)
- Refresh Token — when an access token has expired you can use a refresh token to issue an new access token saving the user having to go through re-authorisation (re-authentication)
- ID Token — validated identity associated with the other tokens
Remember that whilst an OAuth Token can be a JWT it often isn’t.
Endpoints
If you delve further into the standard, there are a range of combinations and permutations. The key ones are “authorize” and “token”.
According to the standard, these can have any name, but everyone generally uses those specific resource names.
Parameters
The parameters (either in the URL, body or claims inside JWTs) are consistent across the standards. There is a great IANA page that lists all the parameters and where they are defined:
This can also help you understand the interplay between the standards.
Anatomy of OAuth
OAuth is made up of many RFCs that build on each other, so their use of terms get overloaded / built upon — adding (each time this happens) nuances and capabilities that are not applicable in all settings. This makes it hard to follow, and can result in incorrect implementations.
A good example is the “JWT”. The standards make sure (quite rightly) that JWTs are used in the same way, fully interchangeable… but it can lead to confusion. You can end up with a solution that has JWTs used for: access token; id token AND for “client authentication”.
On top of that, a practical solution ultimately involves more than one security segment… Meaning you can end up having two overlapping OAuth mechanisms in your solution. For example, OAuth allows on “Authorisation Server” to also act as a “Relying Party” for the next segment.
So the following definitions are rough, to help you get a handle on this.
Authorisation Server
This is the server (or just a service as part of your application) that manages the OAuth issuing of tokens and their associated authorisation decisions. To do this, it needs to store and manage the lifetime of those tokens.
Client
This never refers to a person (which is “end-user” in OAuth terms or “resource owner”), it always refers to the calling software that wants authorisations to access some resources. In 95% of the cases this refers to your web server, not the “client browser”. When OIDC comes into the mix, the “client” is often synonymous with “relying party”
Resource Server
The services being protected by the access tokens issued. On smaller solutions the web application server can be both the resource, authorisation and identity server. API Gateways protected with an in-built OAuth act as both.
Scopes
Scopes… could be your friend, or they can just make life overly complicated. Their use in OAuth are optional, and should be tailored to your use cases. Think of them as transmitting detailed authorisation between parties. If you only have very simple yes/no type authorisations you might simply not need them.
There are different ways to use scopes, in order of importance:
- User consent of what this application can access behind the scenes
- Requesting access to resources
- As a command
Some of the complications for scopes come when:
- Informing your clients what scopes are available
- Scopes are magic strings — the concept comes with a range of pro’s and con’s
- If you use them, make sure there is a logical schema
- Context — when are you requesting a scope? What scopes have been granted?
- What happens if there are multiple OAuth segments? Do you transmit scopes between segments? If you do, you could start to introduce tight coupling between systems
Anatomy of OIDC
Finally, onto OpenID Connect, which is a much needed extension adding an identity layer to OAuth. However, it also adds a number of features that would have been great to have in OAuth type solutions. (In fact, the OpenID discovery endpoints triggered the creation of a draft RFC for OAuth discovery)
The terms used in OIDC, can get re-used when OAuth solutions are in play. This can create confusion, so in any documentation be consistent in their use.
Configuration discovery
OIDC allows for the publication of all the paths for the OIDC endpoints and options that the OIDC provider offers. These claims are published in JSON format with the path suffix of:
- /.well-known/openid-configuration
If you use an OIDC library, you only need one URL to configure the client. Supply the authority path, and on first use the library picks up the OIDC details from the configuration endpoint.
Relying Party (RPs)
The clients of the OIDC Provider (OP), are referred to as “Relying Party” — and is generally a web server application
UserInfo endpoint
Depending on the solution, it might not be feasible to put all the meta-data about an identity into the ID Token. Where this is the case, the “userinfo” endpoint would be used to publish extra information about the authenticated identity.
This is not a search endpoint, it is always specific to the authenticating user — and (unsurprisingly) this endpoint is protected by the access token issued by the OIDC Provider.
Main Links & Further Reading
The key references are the standards themselves:
Worked Example Pages
If you haven’t already go onto these examples: