Audience Verification

When incorporating federated identity, audience verification is important to ensure secure access for your users and customers. Without it, a threat actor can take tokens from a compromised service and use them against your service. This article will cover the identification and resolution of a federated login vulnerability caused by a lack of audience verification.

Federated identity

Applications and services reduce friction by adding federated identity options such as Google, Facebook, Microsoft, and more. By delegating identity to another service, an entire suite of functionality and risk may be delegated alongside it. Tailscale authenticates users with federated identity providers like Google and Microsoft.

A screenshot of tailscale's log in page which has buttons for Google, Microsoft, GitHub, Apple, and passkeys

Because Tailscale authentication is passwordless through federated identity, Tailscale is not at risk from credential stuffing. Google and Microsoft continually mitigate this risk for themselves. As a federated identity user, Tailscale can direct its resources to improving its product, rather than defending against threats to its multi-tenant service.

While Facebook and Google encourage federated identity users — called relying parties — to use a Software Development Kit (SDK), many federated identity providers follow the OpenID Connect (OIDC) specification. It requires relying parties to verify that tokens they receive are intended for them. This check is performed by verifying that the "audience" claim matches their client identity.

These checks occur within the relying party's backend. Either an OIDC library verifies the tokens or a server side SDK by the identity provider does the same. Otherwise, the relying party is rolling their own cryptography which adds incredible risk.

If you are integrating with Google, Microsoft, Facebook, or others, look first towards a provided SDK for your backend of choice. OIDC libraries may provide defaults for commonly-used identity providers. If not, configuring it properly requires expertise and careful review of the identity provider's documentation.

Considering the difficulty in correctly applying an OIDC library and the risks of implementing token verification — I recommend verifying tokens with an identity provider's supplied SDK.

Facebook tokens

I resolved an issue where EatStreet did not use an SDK to verify tokens. The issue was in a hand rolled integration against Facebook's 2014 API. It naively submitted the user supplied opaque token to Facebook's introspection endpoint without any authentication. That endpoint is unable to differentiate clients or bind tokens to one client.

If Facebook had bound token inspection to authenticated clients, where tokens intended for that client could be inspected, then Facebook would have verified that EatStreet was the intended audience for the tokens it inspected. It did not, which made EatStreet vulnerable to an audience verification vulnerability.

Vulnerability disclosure

A security researcher contacted EatStreet to report this vulnerability. They found that tokens submitted to other websites were accepted by EatStreet. Should a threat actor have a source of valid tokens, they could authenticate with the same tokens to websites like EatStreet that did not check that they were the intended audience.

If a user had accounts on both a compromised service and a service under attack, then when that user authenticates with the compromised service, the threat actor could transparently gain access to that user's account elsewhere. Audience verification mitigates lateral access gained through cross-audience token replay.

A diagram where a threat controlled service can relay tokens to a targeted service and gain access to that user's account on that service

To add audience verification to EatStreet, I had to get creative. Facebook's 2014 inspection endpoint does not include the App ID tied to the authentication context. Instead, there is a debug token endpoint which reveals metadata about a token like the App ID that it is bound to.

EatStreet now submits user supplied tokens to the debug token endpoint and verifies the App ID is EatStreet's App ID. This audience verification resolved the vulnerability.

Today, Facebook publishes a Java Business SDK. I recommend migrating any manual integrations with Facebook to an SDK on your backend's platform to secure your users that rely on Facebook federated identity.

OpenID Connect

Open ID Connect (OIDC) is commonly supported by federated identity providers. OIDC is an open set of standards that specify federated authentication with built-in mitigations against vulnerabilities like cross-audience token replay.

Like OAuth 2.0, OIDC is a flexible framework where OpenID Providers combine specified features and requirements to suit their needs. This flexibility creates a lot of complexity for clients, as each OpenID Provider differ from one another.

A few OpenID providers publish discovery endpoints which enable OIDC client libraries to automatically configure themselves to couple with them. Otherwise, the developer must correctly configure the client for each OpenID Provider. Again, this complexity is why I recommend using an SDK for each federated identity provider.

Audience verification in OpenID Connect

OpenID Connect Core specifies thirteen steps to validate an ID Token. Here is an excerpt of a few relevant steps:

Step 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.

Step 4: If the ID Token contains multiple audiences, the Client SHOULD verify that an azp Claim is present.

Step 5: If an azp (authorized party) Claim is present, the Client SHOULD verify that its client_id is the Claim Value.

The above steps hint that ID Tokens may be issued for multiple clients at once. Features like this allow OIDC to support intricate identity integrations between government, finance, healthcare, and others.

Even audience verification is complex to implement, and many other steps are necessary to securely accept ID Tokens. If you are looking to manually implement an OIDC client, I recommend that you prioritize the security of your users by following the recommended integration method supplied by the federated identity provider, rather than implement this technology yourself.

Privacy considerations

Tailscale's login page offers several options without including scripts from each federated identity provider. This choice is privacy respecting by sharing information to Tailscale and not any other party until consent is given.

A truncated screenshot of tailscale's log in page which only shows Google as an option

When a user chooses to click or tap "Google", at that moment, the user has consented to share information with Google. They may freely get signals and data on their own domain from the user to authenticate them.

A truncated screenshot of Google's sign in page

A privacy respecting authentication flow is possible with OIDC. Yet, SDKs from federated identity providers like Facebook track users without regard to their participation or consent.

User client SDKs simplify the log in process at the expense of user privacy. By including scripts and resources from an external provider, a service using federated identity will share user behavior to those providers without the express consent of the user.

A truncated screenshot of EatStreet's sign in page

Backend SDKs, such as the Facebook Java Business SDK and Google OAuth2 API Client Library for Java are more privacy conscious. The client side SDK can reach and relay any details of interest to their provider, while the backend SDK is limited to the information supplied in each function call.

If you are interested in how to validate tokens for Google without an SDK, see Streamlined Linking with OAuth and Google Sign-In for details. However, I recommend using the backend SDK to ensure tokens are securely verified and validated.

If you are interested in moving away from a Facebook client SDK, see OIDC Code Flow with PKCE for Manually Built Facebook Login Flows and Limited Facebook Login.

WebAuthn

WebAuthn includes a similar concept to audience verification: origin binding. "Origin" refers to the website domain that user is connected to. The browser and authenticator ensure security keys are used on the same origin they were created for. The backend that receives authentication assertion must verify the origin matches, much like audience verification.

WebAuthn makes phishing impossible by binding the credentials with the browser's origin. Users can't use WebAuthn for a site they did not register to.
- Configure WebAuthn with Security Keys for MFA by Auth0

In the WebAuthn specification in section 7.2 Verifying an Authentication Assertion, the backend verifying a WebAuthn authentication assertion must perform these steps:

Step 13: Verify that the value of C.origin matches the Relying Party's origin.

Step 15: Verify that the rpIdHash in authData is the SHA-256 hash of the RP ID expected by the Relying Party.

By verifying the origin and relying party, a service mitigates cross-audience authentication assertion replay.

Active security concern

Audience verification is an active security concern, and its mitigations are embedded in protocols such as OIDC and WebAuthn. It is a fantastic target for pen testers and security researchers to explore and submit as a security finding to affected services.

Awareness of audience verification needs to improve. It ought to be included in well-known resources like the OWASP Authentication Cheat Sheet. Consider sharing this resource with your team when you are adding or improving your federated identity choices.