All posts

How to generate an API client ID and client secret

Every API integration starts with the same pair: a client ID that says who is calling and a client secret that proves it. Choosing the format takes minutes. Storing the secret and getting it to the developer is where most of the risk lives.

A client ID names an application, and a client secret proves it. Together they let one system call another without a person logging in. OAuth 2.0 calls this the client credentials flow, and most API platforms use the same pair even when OAuth is not involved: the application presents its ID and secret, and gets access in return.

Generating a good pair is easy. The parts that go wrong are almost always storage and handover, so this covers all three.

One names, the other proves

Think of the client ID as a username for software. It turns up in URLs, in logs, in support conversations and, for apps that run in a browser or on a phone, in code anyone can read. It should be unique, but it does not need to be secret.

The client secret is the password. It belongs in server-side configuration or a secrets manager, never in front-end code, a mobile app or a repository. If it leaks, anyone can act as that application until it is rotated.

Choosing a client ID format

The client ID and secret generator offers three:

  • UUID v4, with 122 random bits. The most widely recognised, and it fits any database column already built for UUIDs.
  • Hex, 128 random bits as 32 characters.
  • Base62, 128 random bits in just 22 characters of letters and digits.

Any of them is fine, because the ID is not a secret. Two things matter more. Make it random, not sequential: numbered clients reveal how many customers you have and invite people to try the next number along. And consider a short prefix, such as acme_, so the ID identifies your product wherever it turns up in someone else's logs.

How long the secret should be

Nobody types a client secret. It is pasted once into configuration and then read by software, so there is no reason to keep it short.

  • 256 bits is the default and the sensible choice. In base62 that is 43 characters.
  • 128 bits is the minimum worth using. It is already far beyond brute force.
  • 512 bits is there for policies that ask for it.

What makes the secret strong is that every bit is random, from a cryptographic random number generator. A long secret built from a timestamp, a hostname or a counter is not strong at all, however long it looks.

Base62, base64url or hex

All three carry the same randomness; they differ in how the result behaves once it exists.

  • Base62 uses only letters and digits. The whole value selects with a double-click, and it never needs escaping in a URL, a header or a .env file. That is why it is the default.
  • Base64url is the same length and just as safe, but its hyphens and underscores break double-click selection, so people copy part of it by mistake.
  • Hex is universally understood and the longest of the three: 64 characters for 256 bits.

Prefixes make leaks findable

A distinctive prefix on the secret, such as acme_sk_, adds no strength. The random part does all of that. What the prefix adds is recognisability.

Secret scanners, including the ones built into code hosting platforms and pre-commit hooks, find leaked credentials by pattern. A random string with no prefix looks like any other random string. A secret that always starts with acme_sk_ can be matched with a simple regular expression in a commit, a log file or a pasted error message, and caught before it does damage. A prefix also tells a person what they are looking at, and a variant such as acme_sk_test_ tells them which environment.

Keep prefixes to letters, digits and underscores, so they need no quoting anywhere. The generator restricts them to characters that are safe in a URL, a header and a .env file.

Storing the secret

On the side that issues the secret, show it once, at creation, and store only a hash. Because the secret is long and random, a single SHA-256 is enough. Slow hashing algorithms such as bcrypt exist to protect short, guessable human passwords; a 256-bit random secret cannot be guessed, so the slowness buys nothing. When a client authenticates, hash what it sent and compare the two in constant time.

On the side that uses the secret, keep it in a secrets manager or in environment variables on the server. The generator produces it ready to paste, as .env or JSON:

CLIENT_ID=3f6c9e2a-41d7-4c5b-9a8e-7b2d1f0c6e94
CLIENT_SECRET=acme_sk_Q4m8ZtR2xV7nK1pL9wB3cH6yF0dJ5sGqE8uTaN2r4kM

If that lives in a .env file, make sure the file is excluded from version control before the first commit, not after.

Rotating without downtime

Secrets should change, both on a schedule and whenever one may have leaked: a contractor leaves, a secret is committed by mistake, or it is pasted into a ticket. Rotation is painless if each client can hold two valid secrets at once:

  1. Issue a second secret alongside the current one.
  2. Update the application to use the new secret, and confirm it works.
  3. Revoke the old secret.

Without the overlap, every rotation is an outage, which in practice means rotations do not happen.

Handing the secret over

The weakest moment in a secret's life is usually the handover. It goes into the ticket that set up the integration, the chat thread with the developer, or the onboarding email, and it stays there, readable by everyone with access, for years after anyone remembers it is there.

Share the pair as a one-time link instead: the generator can hand both values straight to one, and the link shows them once before deleting them. Tell the developer on a different channel that it is coming, so they open it promptly and nobody else gets there first. The guide to sharing credentials with contractors covers the rest of the process.

Common questions

What is the difference between a client ID and a client secret?

The client ID identifies an application, much like a username. The client secret proves that a request really comes from that application, much like a password. The ID can be seen by many people and systems; the secret should be known only to the application and to the service that issued it.

Is a client ID secret?

No. It appears in URLs, logs, dashboards and, for apps that run in a browser or on a phone, in code anyone can inspect. What matters is that it is unique and hard to guess in sequence, not that it is hidden. Random IDs give you both.

How long should a client secret be?

At least 128 random bits, and 256 is a sensible default. Nobody types a client secret, so length costs nothing. In base62, 256 bits is 43 characters. Beyond 128 bits brute force stops being a meaningful threat, and the extra length is cheap insurance.

How should I store client secrets?

Show the secret once, when it is created, and store only a hash of it. Because it is long and random, a single SHA-256 is enough; slow hashes such as bcrypt exist for short human passwords. When a client authenticates, hash what it sends and compare the two in constant time.

How do I rotate a client secret without downtime?

Let each client hold two valid secrets at once. Issue a new one, update the application to use it, confirm it works, then revoke the old one. Rotate on a schedule, and immediately whenever a secret may have leaked.

How do I send a client secret to a developer?

Not in the ticket, chat thread or email that sets up the integration, where it stays readable for as long as they exist. Share it as a one-time link that burns after reading, and tell the developer on a different channel that it is coming.

All posts Share a secret