Skip to main content

LinkedIn

Use Sign In with LinkedIn using OpenID Connect, not the older profile/email permission product. The named driver in released v1.3.0 uses LinkedIn discovery and validates the returned identity token. LinkedIn's sign-in product identifies an account; it does not verify a person's real-world identity. See LinkedIn's current OIDC guide.

Register the application​

Create an application in the developer portal, complete its required organization/application details, and request the Sign In with LinkedIn using OpenID Connect product. Copy your application's client ID and private secret into the server's LINKEDIN_CLIENT_ID and LINKEDIN_CLIENT_SECRET. Never put the secret into browser code.

Register exactly:

https://auth.example.com/auth/oauth2/linkedin/authorization-code-callback

Request openid profile email. The older screenshots below show where application credentials, redirects, and products were configured; current product names differ. Their localhost callback is historical, not the callback used by the example.

Historical LinkedIn redirect registration; use the exact public callback above.

Historical LinkedIn redirect registration; use the exact public callback above.

Configure AuthCrunch​

assets/conf/oauth/linkedin/Caddyfile
# caddy-security v1.3.0 / go-authcrunch v1.3.8. Replace auth.example.com.
{
admin off
persist_config off
security {
oauth identity provider linkedin {
realm linkedin
driver linkedin
client_id {env.LINKEDIN_CLIENT_ID}
client_secret {env.LINKEDIN_CLIENT_SECRET}
scopes openid profile email
}

authentication portal myportal {
enable identity provider linkedin
crypto default token lifetime 900
crypto key sign-verify {env.AUTHCRUNCH_SIGNING_KEY}
ui {
links {
"Example app" /app
"My identity" /auth/whoami
}
}
transform user {
match realm linkedin
action overwrite role authp/user
}
transform user {
match realm linkedin
match sub {$LINKEDIN_ALLOWED_SUB}
action add role app/member
}
}
authorization policy apppolicy {
set auth url https://auth.example.com/auth/
crypto key verify {env.AUTHCRUNCH_SIGNING_KEY}
validate bearer header
allow roles app/member
}
}
}

auth.example.com {
route {
redir /auth /auth/ 308
authenticate /auth/* with myportal
@app path /app /app/*
route @app {
authorize with apppolicy
respond "You reached the protected example app." 200
}
respond "Open /app to begin." 200
}
}

Set AUTHCRUNCH_SIGNING_KEY privately. LINKEDIN_ALLOWED_SUB expands before parsing and must equal the entire observed LinkedIn subject. The example resets provider roles and grants only that account application access. A matching email or portal role is insufficient. LinkedIn can omit email; the bundled parser's default email requirement can then reject login. If your application identifies users by subject, disable email claim check is a deliberate provider option; review the application's identity requirements before enabling it.

The named driver disables PKCE and nonce generation in this release while retaining its state-bound callback and signature/issuer/audience checks. Do not claim it has the same defaults as the generic OIDC driver. It fetches LinkedIn UserInfo for profile data; it does not return arbitrary organization memberships as application permissions.

Verify and troubleshoot​

Sign in through /auth/oauth2/linkedin, inspect /auth/whoami?format=json, and record the exact subject and realm without logging access tokens. Confirm that an intended member reaches /app and another valid identity is denied. A successful provider login alone does not establish application authorization.

Check callback scheme, hostname, port, mount, and realm literally; inspect provider errors and diagnostic logs. Keep client secrets on the server. These examples are parser-verified against the released bundle; console registration, live provider login, consent, and production TLS require verification in your own organization.