Important
This repository is a showcase of reverse-engineering work, not a ready-to-run project. The plugin secret required to run the script is intentionally not included; recovering it requires independently reproducing the relevant reverse-engineering work.
This project is a reverse-engineering experiment exploring how JetBrains' LinkedIn Connected Apps plugin for its IDEs connects to LinkedIn and awards proficiency badges.
The included Python script opens a LinkedIn sign-in page, receives the
authorization callback on localhost, and uses the connected-app flow to
submit selected JetBrains proficiency badges to your profile. You can
choose the IDEs, proficiency levels, display order, and optional top-user
percentile from the command line or from a JSON configuration file.
This is not a JetBrains or LinkedIn product, and it does not install or use the JetBrains IDEs. It is an experiment for learning how the plugin's integration works. The script changes data on a real LinkedIn account, so review the settings carefully before running it.
jetbrains_linkedin_badges_unlocker.py: the command-line script.badges.json: the default badge configuration.examples/shared-defaults.json: an example using shared settings with per-badge exceptions.examples/maxed.json: an example applying the highest level and top-user percentile to every IDE.DISCLAIMER.md: important warnings and responsible-use information.
- Python 3 (developed and tested with 3.14.7)
- A LinkedIn account
- The Python packages listed in
requirements.txt - The
JETBRAINS_PLUGIN_SECRETenvironment variable set to the single valid value (not included in this repository).
Install the packages in a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txtAfter obtaining the secret value, set it without putting it in a file tracked by Git:
export JETBRAINS_PLUGIN_SECRET="your-secret-value"Run the script with its default badges.json configuration:
python jetbrains_linkedin_badges_unlocker.pyThe browser will open for LinkedIn authorization. After approval, the local callback server exchanges the authorization code and submits the configured proficiency badges.
To override the derived external ID, pass it on the command line:
python jetbrains_linkedin_badges_unlocker.py --external-id "your-external-id"When using a JSON configuration file, you can instead add a top-level
externalId string:
{
"externalId": "your-external-id",
"badges": [
{ "ide": "rider", "level": "4-coding" }
]
}The command-line value takes precedence over the configuration value. If neither is supplied, the script derives a stable external ID from the LinkedIn identity token as before.
Useful options include:
# Submit only selected products
python jetbrains_linkedin_badges_unlocker.py --only rider clion
# Use one level for every selected product
python jetbrains_linkedin_badges_unlocker.py --level 3-coding
# Load an example with shared settings and per-badge exceptions
python jetbrains_linkedin_badges_unlocker.py --config examples/shared-defaults.json
# Print redacted API responses while troubleshooting
python jetbrains_linkedin_badges_unlocker.py --debug-apiRun python jetbrains_linkedin_badges_unlocker.py --help for all options.
The local callback listens on port 19191, so that port must be available.
Only use this experiment with accounts and services you are authorized to
access. Confirm that anything shown on your profile is accurate and complies
with the applicable LinkedIn and JetBrains terms. Read
DISCLAIMER.md before using the script.