---
term: 'OAuth 2.0 & Social Login'
seoTitle: 'OAuth 2.0 & Social Login: Flows, Tokens, PKCE, Account Linking'
headline: 'What are OAuth 2.0 & Social Login?'
slug: oauth-2-social-login
category: auth-security
shortDefinition: 'OAuth 2.0 is an authorization standard that lets apps access a user account on another service — social login builds sign-in on top.'
relatedTerms:
  - json-web-token-jwt
  - passwordless-authentication
  - identity-access-management-iam
  - multi-factor-authentication-mfa
contrastsWith:
  - json-web-token-jwt
aboutTerms:
  - 'OAuth 2.0'
  - 'OpenID Connect (OIDC)'
  - 'Social Login'
  - 'PKCE'
faq:
  - question: 'What is OAuth 2.0 in simple terms?'
    answer: 'A standard that lets an app get limited access to your account on another service without you handing over your password. Instead of credentials, the service issues the app a temporary, scoped token — like a hotel key card that opens your room and the gym, but not the manager''s office, and expires at checkout.'
  - question: 'Is OAuth authorization or authentication?'
    answer: 'Authorization — by its own spec title, RFC 6749 is "The OAuth 2.0 Authorization Framework." It answers "what may this app access?", not "who is this user?". Login on top of OAuth is standardized by OpenID Connect, which adds a signed ID token asserting identity to the app.'
  - question: 'What is the difference between OAuth 2.0 and OpenID Connect?'
    answer: 'OpenID Connect is a thin identity layer on OAuth 2.0: same flows, plus a signed ID token (a JWT addressed to your app, with issuer, subject, audience, and nonce claims) and a userinfo endpoint. Every real "Sign in with…" button is OIDC or a provider equivalent — bare OAuth defines no way to prove who logged in.'
  - question: 'What are the OAuth grant types?'
    answer: 'Authorization code with PKCE for anything involving a user; client credentials for machine-to-machine; device authorization for TVs and CLIs; refresh token for renewing access. The implicit and password grants are legacy — both are removed in OAuth 2.1, and new designs should never use them.'
  - question: 'What are access tokens and refresh tokens?'
    answer: 'The access token is the short-lived credential the app presents to the API — scoped, expiring, often a JWT. The refresh token is longer-lived and exchanged for new access tokens without re-prompting the user; modern practice rotates it on every use so a stolen one dies on first replay.'
  - question: 'What is PKCE and why is it required?'
    answer: 'Proof Key for Code Exchange ("pixie"): the app starts the flow with a hashed secret and must present the original when redeeming the authorization code, proving the redeemer is the initiator. Designed for mobile apps that cannot hold client secrets, it defends against code interception — and OAuth 2.1 requires it for every client.'
  - question: 'How does "Sign in with…" actually work?'
    answer: 'The app redirects to the provider''s authorization endpoint; the user authenticates there — the password never touches the app — and consents; the provider redirects back with a one-time code; the app exchanges it for tokens and reads the ID token''s stable subject ID to create or match a local account.'
  - question: 'Is social login safe?'
    answer: 'Generally yes: users get the provider''s hardened authentication and MFA instead of another reused password. The trades are concentration risk — a locked or compromised provider account affects every app downstream — and implementation care: apps must key identity on the provider''s stable subject ID and verified claims, not on a raw email field.'
  - question: 'Does social login improve sign-up conversion?'
    answer: 'Vendor claims of 20–50% registration lift circulate; controlled measurements are humbler — one famous test found about 3%, and roughly a third of consumer sign-ins today are social. The practical consensus: offer the two or three providers your audience actually uses, keep an email fallback, and skip the wall of buttons.'
  - question: 'What if a user signs in with two providers using the same email?'
    answer: 'Decide deliberately: auto-link only on emails the provider attests as verified, or prompt the user to link accounts. Always key the account on each provider''s stable subject identifier — emails change hands and change owners, and trusting an unverified email claim has caused real account-takeover vulnerabilities.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'RFC 6749 — The OAuth 2.0 Authorization Framework'
    url: 'https://datatracker.ietf.org/doc/html/rfc6749'
  - name: 'RFC 7636 — Proof Key for Code Exchange (PKCE)'
    url: 'https://datatracker.ietf.org/doc/html/rfc7636'
  - name: 'OAuth 2.1 — consolidation draft'
    url: 'https://oauth.net/2.1/'
  - name: 'OpenID Connect Core 1.0'
    url: 'https://openid.net/specs/openid-connect-core-1_0.html'
  - name: 'OAuth — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/OAuth'
cta:
  title: 'Social login without the redirect dance'
  text: 'Back4app wraps the whole flow: hand the SDK a provider''s tokens and logInWith verifies them server-side, creates or matches the user, and issues your session — with linkWith solving account linking in one call.'
  linkText: 'Start building free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-07-24'
translationKey: oauth-2-social-login
---

**OAuth 2.0 is an authorization standard that lets apps access a user account on another service — social login builds sign-in on top.** The two are usually explained apart, which is how the confusion survives: [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) defines the plumbing (delegated, scoped access without sharing passwords), OpenID Connect adds the identity layer, and the "Sign in with…" button is the product feature riding both.

## Key takeaways

| Question | Answer |
| --- | --- |
| OAuth 2.0 | Delegated authorization: scoped, expiring tokens instead of passwords |
| The confusion | OAuth answers *what may this app access* — OIDC answers *who is this user* |
| The modern flow | Authorization code + PKCE — implicit and password grants are gone in 2.1 |
| The tokens | Access (short, scoped) · refresh (rotated) · ID (signed identity claims) |
| Social login | OIDC in a button: provider authenticates, your app gets verified claims |

## The authorization code flow, step by step

The redirect dance behind every consent screen — with the parameters that matter:

```text
1  App → provider     /authorize?client_id=…&redirect_uri=…&scope=profile
                      &state=af3G…            ← CSRF guard, checked on return
                      &code_challenge=hK9…    ← PKCE: hash of a fresh secret

2  User ↔ provider    Logs in THERE (password never touches the app), consents

3  Provider → app     redirect_uri?code=SplxlO…&state=af3G…   ← one-time code

4  App → provider     POST /token  { code, code_verifier }    ← PKCE proof
   Provider → app     { access_token, refresh_token, id_token }

5  App → API          Authorization: Bearer <access_token>
```

What that looks like when a backend wraps it — provider tokens in, verified session out:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Social login: the provider's tokens become a user session
const user = await Parse.User.logInWith('apple', {
  authData: { id: appleUserId, token: identityToken },
});
// First login creates the user; later logins match — session token issued

// Account linking: attach a second provider to the same user
await user.linkWith('facebook', { authData: fbAuthData });
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Social login: the provider's tokens become a user session
final user = ParseUser.forQuery();
final response = await user.loginWith(
  'apple',
  apple(identityToken, appleUserId),
);
// First login creates the user; later logins match — session token issued

// Account linking: attach a second provider to the same user
await user.linkWith('facebook', facebook(token, fbUserId, expiresAt));
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Social login: the provider's tokens become a user session
let user = try await User.apple.login(
    user: appleUserId,
    identityToken: identityTokenData
)
// First login creates the user; later logins match — session token issued

// Account linking: attach a second provider to the same user
try await user.facebook.link(userId: fbUserId, accessToken: fbAccessToken)
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Social login: the provider's tokens become a user session
val authData = mapOf("id" to appleUserId, "token" to identityToken)
ParseUser.logInWithInBackground("apple", authData).continueWith { task ->
    val user = task.result
    // First login creates the user; later logins match — session token issued

    // Account linking: attach a second provider to the same user
    user.linkWithInBackground("facebook", fbAuthData)
}
```

## The four roles

| Role | Who it is | In "Sign in with…" terms |
| --- | --- | --- |
| Resource owner | The user | You |
| Client | The app requesting access | The app showing the button |
| Authorization server | Issues codes and tokens | The identity provider's auth pages |
| Resource server | The API guarding data | The provider's profile/user API |

```mermaid
flowchart LR
  accTitle: OAuth 2.0 authorization code flow with PKCE
  accDescr: The client app redirects the user to the authorization server with a PKCE challenge; the user authenticates and consents there; the server redirects back with a one-time code; the client exchanges code plus PKCE verifier for access, refresh, and ID tokens, then calls the resource server with the access token.
  U["User<br/>(resource owner)"] -->|"1 · redirected with<br/>state + code_challenge"| AS["Authorization server<br/>login + consent"]
  AS -->|"2 · one-time code"| C["Client app"]
  C -->|"3 · code + code_verifier"| AS
  AS -->|"4 · access · refresh · ID tokens"| C
  C -->|"5 · Bearer access_token"| RS["Resource server<br/>(API)"]
```

## Grant types: which flow, and what OAuth 2.1 changed

| Grant | For | User present? | Status in [OAuth 2.1](https://oauth.net/2.1/) |
| --- | --- | --- | --- |
| Authorization code + PKCE | Web, mobile, SPA — anything with a user | Yes | **The default — PKCE now required for all clients** |
| Client credentials | Machine-to-machine, service accounts | No | Kept |
| Device authorization | TVs, consoles, CLIs | Yes, on a second device | Kept |
| Refresh token | Renewing access silently | No | Kept — rotation or sender-constraining required for public clients |
| Implicit | Legacy SPAs (tokens in URL fragments) | Yes | **Removed** |
| Password (ROPC) | App collects the password itself | Yes | **Removed** — it defeats the entire point |

OAuth 2.1 is consolidation, not revolution: the deprecations above plus exact-match redirect URIs and a ban on bearer tokens in query strings — the accumulated security lessons of a decade folded back into one document. Definitional explainers largely haven't caught up; several still teach the implicit flow unflagged.

## OAuth vs. OpenID Connect: authorization vs. authentication

The one-liner everyone repeats — "OAuth is not authentication" — deserves its mechanism, because the mechanism is what makes naive login exploitable:

| | Access token (OAuth) | ID token (OIDC) |
| --- | --- | --- |
| Addressed to | The resource server (API) | **Your app** (`aud` = your client ID) |
| Proves | This bearer may access these scopes | This user (`sub`) authenticated at this issuer (`iss`), now (`iat`/`exp`), for this login (`nonce`) |
| Format | Often opaque to the client | Signed [JWT](/glossary/json-web-token-jwt/) your app must validate |
| Safe to log in with? | **No** — any app the user authorized holds one; it says nothing about who is present | Yes — that is its entire job |

"Login with a bare access token" fails because access tokens are transferable evidence of *permission*, not *presence*: a malicious app that obtained a token for its own purposes could replay it to impersonate the user elsewhere. [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) exists precisely to close that gap — same flows, plus an identity assertion cryptographically bound to your app.

## Social login: the button on top of the plumbing

Social login is OIDC packaged as UX: the provider authenticates, your app receives verified claims and creates or matches an account — no password stored, no reset flow owned, the provider's MFA inherited for free. The product trade-offs deserve honest numbers. Registration-lift claims of 20–50% are vendor lore; controlled tests have measured closer to 3%, though roughly a third of consumer sign-ins now arrive socially — users clearly want the option. The practices that actually move conversion: offer **two or three providers** your audience uses (the "NASCAR grid" of buttons measurably hurts), always keep an email fallback, and know that OAuth redirects break inside in-app WebViews — a real driver of mobile signup failure. Two provider-specific facts are load-bearing enough to name: **Sign in with Apple** issues private relay addresses (`…@privaterelay.appleid.com`), so email-keyed linking and mailing lists must expect opaque aliases — and Apple's App Store rules require apps offering third-party sign-in to offer Apple's as well.

## Account linking and the email trap

The same person will arrive from two providers, and both will report `ada@example.com`. The rule that prevents the classic vulnerability: **identity keys on the provider's stable `sub` identifier, never on email alone.** Emails change, get recycled, and — the sharp edge — are not always verified: a 2023 vulnerability class showed apps that trusted an unverified email claim from a major provider's tokens were open to account takeover by anyone who could set that email on their own provider account. Auto-link only on provider-attested verified emails; otherwise prompt the user to link explicitly. And plan for the exit: users locked out of a provider (it happens without warning) lose every app downstream unless you offered a second linked method — which is why "one login method per user" is a support-ticket generator wearing a simplicity costume.

## Common use cases

- **Consumer app sign-in** — the canonical social login: lower friction, inherited MFA, no password database to breach.
- **Third-party API access** — the original OAuth case: a scheduling app reading your calendar without your password.
- **Machine-to-machine auth** — client credentials between services, no user in sight.
- **Multi-provider identity** — one account, several linked login methods, per-user unlink and recovery.
- **Enterprise SSO bridging** — the same OIDC pattern pointed at a workforce identity provider instead of a social one.

## Should you offer social login? A decision matrix

| Your situation | Lean |
| --- | --- |
| Consumer app, mobile-heavy audience | Yes — 2–3 providers + email fallback |
| iOS app offering any third-party login | Apple's sign-in becomes required — plan for relay emails |
| B2B/enterprise product | OIDC yes, but toward workforce SSO, not social |
| Regulated data, strict account lifecycle | Careful — provider lockout and identity proofing need answers |
| MVP needing auth this week | Yes, via a backend that wraps the flows |
| Users without accounts at major providers | Email/passwordless first; social as an option |

## Limitations and trade-offs

- **You inherit the provider's decisions.** Consent screens, session lifetimes, account recovery, and deprecations happen on their schedule, not yours.
- **Concentration risk is real.** A provider outage or account lockout is your login outage; linked fallback methods are the mitigation, not an optional extra.
- **OAuth's flexibility is its historical weakness.** A framework with options invites insecure combinations — the reason 2.1 exists is that implicit flows, wildcard redirects, and unrotated refresh tokens kept shipping.
- **Redirect flows have sharp edges.** `state` (CSRF), exact redirect URIs (open-redirect and code theft), and PKCE (interception) are each one missing parameter away from an incident.
- **Social claims are a floor, not a profile.** You get subject, email, name — attributes beyond that still need your own onboarding, and privacy relays mean even email may be an alias.

## OAuth and social login on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. The flows above collapse into the code tabs: the client obtains the provider's tokens natively, hands them to `logInWith`, and Back4app's auth adapters verify them server-side against the provider before creating or matching the `User` — provider identities live in per-provider `authData` blocks keyed on the stable subject ID, which is the account-linking rule enforced by construction. `linkWith` attaches additional providers (or an email credential) to the same user, answering the lockout problem in one call, and the session token your app receives then works across the REST, GraphQL, and Live Query APIs with [ACLs](/glossary/access-control-lists-acl/) and class-level permissions deciding what it may touch. The redirect dance, token verification, and linking edge cases arrive as platform behavior — you configure providers in the dashboard and ship the button.
