Bearer tokens provide a compact way to authenticate HTTP requests against APIs without sending raw credentials on every call. Instead of repeating usernames and passwords, an application presents a short-lived string in the Authorization header so the server can identify and authorize the client. This approach is common for microservices, web backends, CLI tools, and mobile applications that communicate with REST or GraphQL endpoints.

Most modern APIs issue bearer tokens through OAuth 2.0 or compatible identity providers. A client first exchanges credentials or a refresh token at a token endpoint, which returns JSON containing an access_token, an optional refresh_token, a lifetime, and a token_type that is usually Bearer. With curl, an access token becomes a regular header value that can be attached to any HTTP method by sending Authorization: Bearer <token>.

Bearer tokens behave like passwords for their lifetime and must be handled as sensitive secrets. Plain-text copies in shell history, world-readable files, or logs allow anyone with access to those locations to impersonate the client until the token expires or is revoked. Secure storage, strict file permissions, and predictable refresh flows reduce the risk of leaks while keeping automation convenient.

Steps to authenticate with bearer token in curl:

  1. Run a basic version check for curl in a terminal session.
    $ curl --version
    curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 libidn2/2.3.2 libpsl/0.21.0
    Release-Date: 2022-02-09
    Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s smtp smtps telnet tftp
    Features: alt-svc AsynchDNS HTTPS-proxy IPv6 libz TLS-SRP
    ##### snipped #####

    Any recent curl build with HTTPS and custom header support is suitable for bearer-token APIs.

  2. Request an access token from the OAuth 2.0 token endpoint using client credentials.
    $ curl --request POST "https://auth.example.com/oauth/token" \
      --header "Content-Type: application/x-www-form-urlencoded" \
      --data "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
    {
      "access_token": "YOUR_ACCESS_TOKEN",
      "token_type": "Bearer",
      "expires_in": 3600,
      "scope": "read write"
    }

    Placeholder values YOUR_CLIENT_ID and YOUR_CLIENT_SECRET represent confidential credentials issued by the authorization server.

  3. Export the returned access token into an environment variable for reuse in subsequent commands.
    $ export ACCESS_TOKEN="YOUR_ACCESS_TOKEN"
    $ printf '%s\n' "${ACCESS_TOKEN}"
    YOUR_ACCESS_TOKEN

    Environment variables reduce repetition in commands but still hold secrets in process context, so clearing or rotating them regularly limits exposure.

  4. Call a protected API endpoint by sending the bearer token in the Authorization header.
    $ curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
      "https://api.example.com/data"
    {
      "data": "sample data response",
      "status": "ok"
    }

    The Authorization header must exactly match the expected format Authorization: Bearer <token> or the server may treat the request as anonymous.

  5. Inspect the outgoing HTTP exchange using verbose mode to verify that the Authorization header is sent.
    $ curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
      "https://api.example.com/data" \
      --verbose
    > GET /data HTTP/1.1
    > Host: api.example.com
    > Authorization: Bearer YOUR_ACCESS_TOKEN
    > User-Agent: curl/7.81.0
    > Accept: */*
    ##### snipped #####

    Verbose output prints headers to the terminal and potentially to log files, which can expose tokens on shared systems.

  6. Store the Authorization header in a restricted curl configuration file for repeated local use.
    $ echo 'header = "Authorization: Bearer YOUR_ACCESS_TOKEN"' > .bearer_token
    $ chmod 600 .bearer_token
    $ ls -l .bearer_token
    -rw------- 1 user user 60 May 27 10:15 .bearer_token

    World-readable configuration files allow other local users to replay the bearer token until it expires or is revoked.

  7. Use the configuration file when sending authenticated API requests.
    $ curl --config .bearer_token "https://api.example.com/data"
    {
      "data": "sample data response",
      "status": "ok"
    }

    --config reads options and headers from the specified file so scripted calls remain shorter and consistent.

  8. Exchange a refresh token for a new access token when the original token expires.
    $ curl --request POST "https://auth.example.com/oauth/token" \
      --header "Content-Type: application/x-www-form-urlencoded" \
      --data "grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
    {
      "access_token": "NEW_ACCESS_TOKEN",
      "token_type": "Bearer",
      "expires_in": 3600
    }

    Refreshing tokens on a schedule avoids authentication failures when the original access_token reaches its expires_in limit.

  9. Check the HTTP status code to confirm that the bearer token is accepted.
    $ curl --config .bearer_token \
      --write-out "%{http_code}\n" \
      --silent \
      --output /dev/null \
      "https://api.example.com/data"
    200

    HTTP status codes 200 or 201 typically indicate success, while 401 Unauthorized or 403 Forbidden suggest token issues or insufficient scope.

Discuss the article:

Comment anonymously. Login not required.