Choosing LinkedIn Authentication for Public Web Apps: OAuth 2.0 vs SAML SSO
Choose the right LinkedIn authentication for your public web app. This guide recommends OAuth 2.0 over SAML SSO, compares the options, and walks through a Spring Boot implementation with verification steps.
30 Apr 2026, 18:52 UTC

Problem: How to let users sign in with LinkedIn
Public web applications often need a lightweight, single‑sign‑on experience. LinkedIn offers two main mechanisms: OAuth 2.0 and SAML SSO. The decision hinges on the app’s audience, required data, and infrastructure.
Decision: Adopt LinkedIn OAuth 2.0
For consumer‑facing sites that only need basic profile data, OAuth 2.0 is the simplest, most compliant path. It requires only a client ID/secret, grants fine‑grained scopes, and keeps the integration lightweight.
Constraints to Observe
- Follow LinkedIn’s API Terms of Service – no persistent storage of access tokens without encryption.
- Keep the client secret in a secure environment variable or vault; never commit it to source control.
- Use only the scopes you need:
r_liteprofilefor name and headline,r_emailaddressfor the user’s primary email. - Respect the 60 calls/minute rate limit; cache profile data wherever possible.
Comparison Table: OAuth 2.0 vs SAML SSO
| Feature | OAuth 2.0 | SAML SSO |
|---|---|---|
| Typical Use | Public consumer apps | Enterprise‑to‑enterprise SSO |
| Setup Complexity | Client ID/secret + redirect URI | IdP/SSO provider, metadata exchange |
| Security Model | Bearer token, short‑lived | Signed SAML assertions, role‑based |
| Data Access | Scopes control fields | All attributes in assertion |
| Maintenance | Refresh token rotation only if needed | Metadata rotation, certificate renewal |
| Compliance Risk | Low (no token storage) | High (must secure IdP certificates) |
Trade‑offs
- Speed vs Control: OAuth is fast to integrate but you cannot request arbitrary user attributes; SAML gives full attribute control but requires an IdP.
- Token Lifecycle: OAuth tokens expire quickly (typically 60‑90 min). If your app needs long‑term access to the LinkedIn API, you must handle refresh tokens, which LinkedIn does not provide for user scopes.
- Infrastructure Overhead: SAML demands an SSO server or a third‑party IdP, which adds operational cost and complexity.
- Compliance: OAuth’s short‑lived tokens reduce the risk of data leaks; SAML assertions are longer‑lasting and must be stored securely.
Concrete Spring Boot Implementation
1. Add Dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. Configure application.yml
spring:
security:
oauth2:
client:
registration:
linkedin:
client-id: ${LINKEDIN_CLIENT_ID}
client-secret: ${LINKEDIN_CLIENT_SECRET}
redirect-uri: '{baseUrl}/login/oauth2/code/linkedin'
authorization-grant-type: authorization_code
scope: r_liteprofile, r_emailaddress
provider:
linkedin:
authorization-uri: https://www.linkedin.com/oauth/v2/authorization
token-uri: https://www.linkedin.com/oauth/v2/accessToken
user-info-uri: https://api.linkedin.com/v2/me
user-name-attribute: id
3. Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(a -> a
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated())
.oauth2Login(o -> o
.loginPage("/oauth2/authorization/linkedin"))
.logout(l -> l.logoutSuccessUrl("/public").permitAll());
}
}
4. Fetch User Profile
@RestController
public class ProfileController {
@GetMapping("/profile")
public Map<String, Object> profile(OAuth2AuthenticationToken authentication) {
OAuth2AuthorizedClient client = (OAuth2AuthorizedClient) authentication.getPrincipal();
String accessToken = client.getAccessToken().getTokenValue();
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
headers.set("X-Restli-Protocol-Version", "2.0.0");
HttpEntity<Void> entity = new HttpEntity<>(headers);
// Basic profile
ResponseEntity<Map> me = rest.exchange(
"https://api.linkedin.com/v2/me",
HttpMethod.GET,
entity,
Map.class);
// Email address
ResponseEntity<Map> email = rest.exchange(
"https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))",
HttpMethod.GET,
entity,
Map.class);
Map<String, Object> result = new HashMap<>();
result.put("profile", me.getBody());
result.put("email", email.getBody());
return result;
}
}
5. Persist User (Optional)
Map the returned JSON to a User entity and store only non‑sensitive fields (e.g., firstName, lastName, email). Do not persist the access token.
Verification Checklist
- Register a LinkedIn app, enable OAuth 2.0, and set the redirect URI to
https://yourapp.com/login/oauth2/code/linkedin. - Set
LINKEDIN_CLIENT_IDandLINKEDIN_CLIENT_SECRETin your environment. - Run the Spring Boot application locally:
./mvnw spring-boot:run. - Navigate to
http://localhost:8080/oauth2/authorization/linkedinand log in with a LinkedIn account. - After redirection to
/login/oauth2/code/linkedin, open the browser console or check logs for a successful authentication message. - Visit
/profileand confirm the JSON contains fields such aslocalizedFirstName,localizedLastName, andemailAddress. - Check application logs for any OAuth errors and ensure they are handled gracefully.
Limitations and Practical Checks
- LinkedIn enforces a 60 calls/minute per app limit. Cache profile data in memory or a short‑lived cache to stay within the quota.
- If you omit
r_emailaddress, the email endpoint will return a 401 error. Verify scopes in the LinkedIn developer console. - Storing access tokens in a database without encryption violates LinkedIn’s TOS. Keep them only in the HTTP session.
- Any change to the redirect URI must be updated in the LinkedIn app settings; otherwise, LinkedIn will reject the authorization code.
- LinkedIn may update endpoint URLs or required parameters. Periodically review the LinkedIn OAuth documentation before deploying new releases.
Conclusion
For a public web application that needs a quick, compliant way to let users sign in with LinkedIn, OAuth 2.0 is the recommended path. It balances developer productivity, security, and compliance while providing the essential profile data required for onboarding. SAML SSO remains an option for enterprise deployments where a full identity federation solution is already in place.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.