skip to content

In Git, how do https:// and ssh:// remote URLs differ in how they authenticate?

level: juniorimportance: must knowfreq 74%

answer

  1. The scheme decides who proves what
  2. One shells out to another program
  3. One asks a helper for a secret per request
  4. Keys versus tokens
  5. Port 443 versus port 22

basics

~20 s

An https:// remote authenticates per request with a username and a token, supplied by a credential helper over a TLS connection. An ssh:// remote shells out to ssh, which authenticates with a key pair; the server then runs git-upload-pack or git-receive-pack over that channel.

solid answer

~40 s

With an `https://` remote, Git speaks smart HTTP over TLS and needs a username and secret for each authenticated request. It asks the configured `credential.helper` first, and prompts only if no helper answers; most hosts now expect a personal access token rather than an account password in that field. With an `ssh://git@host/org/repo.git` remote — or the equivalent scp-like form `git@host:org/repo.git` — Git shells out to the system `ssh` client, which authenticates with a key pair from `~/.ssh` or an agent, and the server then runs `git-upload-pack` or `git-receive-pack` on the other end of that channel. There is also the legacy `git://` transport, which is anonymous, read-only, unencrypted and unauthenticated; it should not be used for anything private. Switching between them is just `git remote set-url`.

code

bash · 6 lines
bash
git remote -v
# origin  [email protected]:acme/app.git (fetch)
# origin  [email protected]:acme/app.git (push)

git remote set-url origin https://example.com/acme/app.git
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ed25519_ci" git ls-remote [email protected]:acme/app.git

go deeper

for a junior

Be able to read a remote URL and say how it will authenticate: a key pair for the SSH forms, a username and token for HTTPS. Know git remote -v and git remote set-url.

for a middle

Explain that Git shells out to ssh for SSH remotes while HTTPS goes through the credential-helper mechanism, and name the server-side programs the transports invoke.

for a senior

Argue the operational tradeoffs — proxy traversal, container ergonomics, host-key verification, credential rotation — rather than repeating a preference for one scheme.

for a principal

Own which transport the organization standardizes on for humans and for automation, and what that implies for firewall rules, secret rotation and onboarding.

## The transports Git speaks A remote URL's scheme selects a transport, and each transport has its own authentication story. **HTTPS** — `https://host/org/repo.git`. Git makes HTTP requests to the server's Git endpoints over TLS. TLS authenticates the *server* and encrypts the channel; the *client* proves who it is with an HTTP credential, conventionally a username plus a secret. Most hosts have stopped accepting an account password here and expect a personal access token instead — a separately issued secret with its own permissions and expiry, revocable without changing your login. **SSH** — `ssh://git@host/org/repo.git`, or the older scp-like shorthand `git@host:org/repo.git` (note the colon, and that it takes no port; use the full `ssh://` form when you need `-p`-style port selection). Git does not implement SSH itself; it executes the system `ssh` binary, which performs public-key authentication using a key from `~/.ssh` or from a running `ssh-agent`. Once authenticated, the client asks the server to run `git-upload-pack` (for fetch) or `git-receive-pack` (for push), and the Git protocol flows over that channel. **git://** — the daemon protocol on port 9418. It has no authentication and no encryption. It exists for fast anonymous public mirrors and is unsuitable for anything private. **file://** and a plain local path also work, useful for local mirrors and tests. ## Where the secret lives in each case For SSH, the secret is a private key file on disk, usually protected by a passphrase and unlocked once into `ssh-agent`. Git itself never sees it. You can point Git at a specific key or ssh invocation with `core.sshCommand` or the `GIT_SSH_COMMAND` environment variable — useful when one machine must use different identities for different hosts. For HTTPS, the secret reaches Git through the credential-helper mechanism (`credential.helper`), which may store it in an OS keychain, in memory for a while, or in a plaintext file. Without a helper Git prompts on the terminal every time. ## Practical differences that decide the choice - **Firewalls and proxies.** HTTPS uses port 443 and passes through corporate proxies that block port 22. This is often the deciding factor. - **Container and CI ergonomics.** HTTPS needs one secret in an environment variable and a helper or askpass hook. SSH needs a key file with correct permissions, a known-hosts entry, and usually an agent — more moving parts inside a minimal image. - **Host verification.** SSH verifies the server by its host key against `known_hosts`; a first connection to an unknown host either prompts or, in a non-interactive job, fails. HTTPS verifies the server via the TLS certificate chain, which needs no per-user setup. - **Rotation.** Tokens usually carry an expiry and can be scoped narrowly; SSH keys typically live until someone removes them. ## Mixing them A repository can have several remotes with different transports, and `url.<base>.insteadOf` can rewrite one form into the other globally — handy when a `.gitmodules` file hardcodes SSH URLs but a CI job only has an HTTPS token. `git remote -v` shows what each remote currently uses, and `git remote set-url origin <new>` switches it.

  • What is the difference between git@host:org/repo.git and ssh://git@host/org/repo.git?
    They select the same transport. The first is the scp-like shorthand, where the colon separates host from path and no port can be given. The second is the full URL form, which accepts an explicit port and a leading slash on an absolute path. When a non-default port is involved, the `ssh://` form is required.
  • Why do hosts require a token instead of an account password over HTTPS?
    A token is a separate credential with its own scope and expiry, so it can be limited to specific operations and revoked without touching the account itself. It also survives the interactive login flows an account password is now wrapped in. From Git's point of view nothing changes: the token is simply what goes in the password field.
  • When would you deliberately use the git:// transport?
    Only for anonymous read access to public content where speed matters more than integrity guarantees, such as a public mirror. It is unauthenticated and unencrypted, so anyone on the path can observe or tamper with what you fetch. For anything private, or anything you will build and run, use HTTPS or SSH.

saying these in an interview costs you the question

  • Thinks SSH keys authenticate HTTPS remotes too
  • Says TLS proves who the client is
  • Believes git:// is just HTTPS without a certificate
  • Assumes changing the URL scheme changes the repository
  • Treats a personal access token as the account password

context