There are several ways to authenticate when requesting a Token, for a good overview of them checkout https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified. The most common types are:
- Authorization Code - For web applications, run on the server. Also referred to as "Trusted Application"
- Implicit - For mobile or javascript applications, run on the client. Also referred to as "Untrusted Application"
- Resource Owner Password Credentials - Used when the users password is stored in the application, useful for scheduled events like backup scripts or "canonical" apps.
- Client Credentials - For actions not invoked by a User or when user authentication is done by the Application and any required user details are passed to the backend in the payload.
- SAML2 Bearer Assertion - Allows the web application to pass along the assertion it received from the user signing into SSO.
Client Credentials are the simplest to implement and therefore a good starting point.
Terms
Speaking about the OAuth flow it is important to clearly define some of the common terms. The terms used throughout this document are defined below.
Term | a.k.a | Definition | Example |
---|---|---|---|
Resource | The protected data or service. | Mary's Facebook Account. | |
Resource Owner | User | The entity that grants permission to use a Resource. Often also the user of the application. | Mary |
Resource Server | API Server | The server that hosts the Resource. | Facebook's Data Server |
Client | Application | The application that wants to use the Resource. | GreetingCardMaker |
Authorization Server | Token Manager | The server responsible for authenticating the Resource Owner and determining their concent. The Resource Server trusts the Authorization Server and they are almost always run by the same organization. Often the Resource Server and Authorization Server are the same thing. | Facebook's OAuth Server |
Client ID & Secret | App Username/Password | The credentials that a Client application uses to authenticate with the Authorization Server. These are usually generated when the Client is registered with the Authorization Server. |
|
Username & Password | The credentials that the Resource Owner uses to authenticate with the Authorization Server. | Mary's Facebook username and password. | |
OAuth Token | Bearer Token | A short lived token that is issued to the Client by the Authorization Server after authenticating and getting permission from the Resource Owner. | A short random string. |
Authorization Grant | Grant Code | A representation of the Resource Owner's consent for the Resource to be released to a Client. The Authorization Grant is provided by the Client to the Authorization Server (along with the Client ID & Secret) in exchange for an OAuth Token. Each Authorization Grant is limited to a specific Client, Resource Owner and Scope. | A short random string. |
Scope | A subset of the Resource. | Facebook Photo's, Contacts, Status etc. |
Authorization Code - Trusted Application
Authorization Code is the most commonly used form, it is used by giants like Facebook and Twitter. First the application authenticates with the Server, then the user is asked if they allow their data to be released to the application. This authentication and permission are translated by Server to an access token.
In some Authorization Server implementations it is considered redundant to ask the Resource Owner for consent and authentication is considered consent. This is the case for UCSD's API Manager; it was determined that users wouldn't know why they were being asked the question and that the answer should always be yes, so the option is never presented.
Flow:
- The Client ID & Secret are compiled into the application.
- Users of the application are sent to the Authorization Server to provide their consent. The Client ID and requested Scope are encoded in the url.
- The Authorization Server returns a Authorization Grant to the Client.
- The Client gives the Authorization Grant and Client ID & Secret to the Authorization Server.
- The Authorization Server returns a OAuth Token.
- The Client invokes api on the Resource Server, passing along the OAuth Token.
Example:
Pros and Cons:
- The Client Secret must be stored in the application. If the source of the application is readable then this option won't work.
- The User must be present to grant consent. Although most Authorization Servers save the Resources Owners preferences.
Implicit - Untrusted Applications
The implicit Grant type is designed specifically for instances where the Client cannot securely store the Client Secret, such as with HTML/Javascript apps. Because the Client cannot authenticate with the Authorization Server to retrieve the OAuth Token, it is instead passed on the URL of the Client when the user is returned from the Authorization Server. The OAuth Token will be an Anchor Parameter (Fragment Identifier) in order to reduce the exposure; when rendering a URI the browser does not include the Fragment Identifier when fetching the resource, but it is available to JavaScript that runs in the returned page.
Flow:
- Users of the application are sent to the Authorization Server to provide their consent. The requested Scope is encoded in the url.
- The Authorization Server redirects the browser to the Client's callback URL with the OAuth Token as a fragment identifier.
- The Client extracts the OAuth Token from the browsers location.
- The Client invokes APIs on the Resource Server, passing along the OAuth Token.
Example:
Pros & Cons
- TheClient Secret does not need to be compiled into the application. This enables it to run in untrusted environments, like the user's browser.
- The OAuth Token is passed as part of the URI, not in a response body.
- Traditionally the URI is considered less secure than the body, for example webservers often log the incoming URIs but not message bodies.
- The following facts/choices help mitigate the security concerns:
- The Fragment Identifier does not get passed to the web server, so it cannot be logged.
- SSL encrypts everything in the URI except the host and port. The Fragment Identifier is encrypted during transport.
- The major remaining concern is the browser history, see below.
Browser History Attack
The largest vulnerability that we have identified is that browsers often store URI's in their history. This history persists across browser restarts, which allows the following attack.
- User Alice launches a browser and accesses an application that uses Implicit Grant type. Alice is issued a OAuth Token which the JavaScript client stores in a cookie. The token is valid for 15min.
- Alice completes her work, closes the browser and leaves the room.
- Eve launches the same browser and accesses the same application, within the 15min window.
- The cookie is not present because it was session scoped.
- Eve checks the browser history and selects a recent URI that includes an OAuth Token.
- The Client detects the OAuth Token on the URI and stores it as a new cookie.
- The Client can now invoke APIs with Alice's permissions.
The Client JavaScript could be written to detect and avoid this issue, by setting a "request_sent" cookie when sending the user to the Authorization Server and only parsing OAuth Tokens if that cookie is present.
Fundamentally this does not eliminate the problem as once Eve sees the token in the browser history she can use it in her own custom code.
One possible remedy is to provide a "Logout" feature that invokes the Authorization Server's revoke API. This however relies on that API call working and the user clicking on LogOut.
Why include the OAuth Token on the URI?
The Implicit Grant type was designed with JavaScript apps in mind. Lets look at the possible data transmission channels as they pertain to a JavaScript app being served by Apache:
- POST message body - The request body is used by the server to determine what response to send, or in the case of Apache it is ignored. JavaScript runs on the HTML included in the response, the request body is not available.
- HTTP Headers - Headers set by the Authorization Server would likewise be request headers on the receiving end; request headers are not available to JavaScript.
- Client fetches the OAuth Token - Without a shared secret the Authorization Server has no way to confirm the request is coming from the proper Client.
- Query Params or URI Filename - The Fragment Identifier is the most protected part of the URI, all other parts are passed by the browser to the web server where it could be logged or worse.
This problem has been the subject of significant consideration and while not optimal the Fragment Identifier seems the best solution.
Possible Solution: One Time Tokens
It has been proposed that the Authorization Server could send back a One Time Token instead of the OAuth Token. The Client would then make a GET request to the Authorization Server to exchange the One Time Token for a OAuth Token. As the name indicates, the One Time Token would only be valid for one such exchange and have a much shorter TTL (~2min).
The Browser History Attack would be impossible, as the only time any token is placed in the browser history it is invalidated by that same call.
An alternative proposal is that One Time Tokens behave as normal OAuth Tokens but are only good for a single use (or a very small window ~30sec from first use).
Neither concept is not part of the OAuth spec and is not supported by WSO2's products.
WSO2 has expressed interest in such a feature (more likely the alternative version) but has not placed it on any road map. WSO2's products are designed for extensibility so it is entirely possible to write a 3rd party Grant Type and API that would implement this feature.
Resource Owner Password Credentials - Thick Client / Script
With the Resource Owner Password Credentials grant type the Client submits it's own Client ID & Secret along with the Resource Owner's Username & Password. The motivation for this grant type is "canonical" apps, for example the Facebook app on a mobile device might ask for the users Facebook password and use Resource Owner Password Credentials.
Flow:
- The Client requests and stores the Username & Password from the Resource Owner. This can be done in advance of the other steps and persist over sessions.
- The Client submits to the Authorization Server the Client ID & Secret along with the Username & Password.
- The Authorization Server returns a OAuth Token. There is now "consent" screen as the user has give all control to the Client by turning over their Password.
- The Client invokes APIs on the Resource Server, passing along the OAuth Token.
Example:
Pros & Cons:
- Requires the user to turn over their Username & Password, which users should be very wary of doing. Which is why this is usually restricted to "canonical" apps (e.g. the Facebook App -> Facebook API).
- App has responsibility of securely storing the Password. The Password cannot be stored as a salted hash as is normally advised, because the request to the Authorization Server requires the original plain text (Base64 Encoded) Password.
- The User doesn't have the authenticate every time they use the app.
- The App can act on the users behalf without user input, for example the App can check for new messages in the background.
Client Credentials
The Client Credentials grant type was designed for operations that the App is performing on it own behalf. This could be a backup script that isn't designed to run as a particular user or a webapp doing a background task that is not related to the user currently invoking it. This is the simplest of the grant types, but also provides the least information to the API Manager for access decisions and statistics.
Because the APIM will not know what user is driving the operation it can not pass this information onto the Backend.
When the application is invoking an API because of input from the User, Authorization Grant should be used instead. However that requires the user be sent to the APIM to authenticate and give consent. In circumstances where consent is automatic or assumed and the User has already authenticated to the Application (e.g. webapp behind SSO) it is acceptable to use Client Credentials. The application should include any User details needed by the backend server in the payload as the APIM won't be able to provide any User information.
Flow:
- Client requests a token from the Authorization Server, including the Client ID & Secret.
- The Authorization Server returns an OAuth Token.
- The Client invokes APIs on the Resource Server, passing along the OAuth Token.
Example:
Pros & Cons:
- Simple.
- No need for "fake" users or service accounts.
- API Manager can not consider User when determining permissions (if there is one).
- API Manager cannot log which User was involved (if there is one)
SAML2 Bearer Assertion
When a web app sends the user to SSO for authentication, the SSO server returns a signed SAML Assertion. This assertion includes the known data about the current user, such as username. If the Authorization Server also trusts the SSO Server, then that signed SAML Assertion can be exchanged for a OAuth Token.
Flow:
- Client sends user to SSO for authentication.
- The user authenticates with the SSO server, usually with a username/password.
- The SSO returns an assertion to the Client, proving that the current user has authenticated.
- The Client requests an OAuth Token from the Authorization Server, including the SAML Assertion.
- The Authorization Server verifies the assertion was signed by a trusted IDP and returns an OAuth Token.
Example:
Pros & Cons:
- User only has to authenticate once.
- However in the normal scenarios, if the Authorization Server uses the same SSO IDP, when the user is sent to authenticate they will already have a session and be returned immediately. The end result is that the user only gets prompted for their username/password once.
- The SAML Assertion has to be in a format that both the Client and Authorization Server can process.
- In particular, the WSO2's Identity Server has configurations for extracting and transforming SAML assertions but these are not available in the SAML2 Bearer Assertion grant type.
Notes:
Below is the code used on https://www.websequencediagrams.com/ to generate the diagrams above.
title Authorization Code participant FB Auth participant Mary participant GreetingCardMaker participant FB Photos Mary->GreetingCardMaker: Click "Load Facebook Photos" GreetingCardMaker->Mary: Redirect (ClientID: GreetingCardMaker, Scope: Photos) Mary->FB Auth: Authorization Request note over Mary, FB Auth: Authenticate & Grant Permission FB Auth->Mary: Redirect (Grant Code) Mary->GreetingCardMaker: (Grant Code) GreetingCardMaker->FB Auth: Request Token (Client ID & Secret, Grant Code) FB Auth->GreetingCardMaker: OAuth Token GreetingCardMaker->FB Photos: Request Photos (OAuth Token) FB Photos->GreetingCardMaker: Mary's Photos
title Implicit Grant Type participant FB Auth participant Mary participant GreetingCardLite.html participant FB Photos Mary->GreetingCardLite.html: Click "Load Facebook Photos" GreetingCardLite.html->Mary: Redirect (ClientID: GreetingCardLite, Scope: Photos) Mary->FB Auth: Authorization Request note over Mary, FB Auth: Authenticate & Grant Permission FB Auth->Mary: Redirect (OAuth Token)\nhttps://server/GreetingCardLite.html#access_token=8de... Mary->GreetingCardLite.html: OAuth Token GreetingCardLite.html->GreetingCardLite.html: Extract OAuth Token\nfrom window.location.href GreetingCardLite.html->FB Photos: Request Photos (OAuth Token) FB Photos->GreetingCardLite.html: Mary's Photos
title Resource Owner Password Credentials participant Mary participant FB App participant FB Auth participant FB Photos Mary->FB App: Stores Username & Password FB App->FB Auth: Get Token\n(Client ID & Secret, Username & Password, Scope) FB Auth->FB App: OAuth Token FB App->FB Photos: Request Photos (OAuth Token) FB Photos->FB App: Mary's Photos
title Client Credentials participant Auth Server participant BackupScript participant API Manager BackupScript->Auth Server: Request OAuth Token (Client Id & Secret) Auth Server->BackupScript: OAuth Token BackupScript->API Manager: Report Successful backup (OAuth Token)
title SAML2 Bearer Assertion participant A4 participant Mary participant MyTime participant Auth Server Mary->MyTime: Access MyTime MyTime->Mary: Redirect to A4 Mary->A4: Authenticate note over Mary, A4: Authenticate A4->Mary: SAML Assertion Mary->MyTime: Access MyTime (SAML Assertion) MyTime->MyTime: Process Assertion, \nextract user data. MyTime->Auth Server: Request OAuth Toke (SAMl Assertion) Auth Server->Auth Server: Verify Signed by trusted IDP Auth Server->MyTime: OAuth Token MyTime->Leave Balances API: get user's vacation time (OAuth Token)