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 a bearer token in cURL:
- Run a basic version check for curl in a terminal session.
$ curl --version curl 8.5.0 (aarch64-unknown-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.7 Release-Date: 2023-12-06, security patched: 8.5.0-2ubuntu10.6 Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd ##### snipped #####
Any recent curl build with HTTPS and custom header support is suitable for bearer-token APIs.
- Request an access token from the OAuth 2.0 token endpoint using client credentials.
$ curl --silent --request POST "https://api.example.net/oauth/token" \ --header "Content-Type: application/x-www-form-urlencoded" \ --data "grant_type=client_credentials&client_id=demo-client&client_secret=demo-secret" { "access_token": "access_123", "expires_in": 3600, "refresh_token": "refresh_456", "token_type": "Bearer" }Placeholder values demo-client and demo-secret represent confidential credentials issued by the authorization server.
- Export the returned access token into an environment variable for reuse in subsequent commands.
$ export ACCESS_TOKEN="access_123"
$ printf '%s\n' "${ACCESS_TOKEN}"
access_123
Environment variables reduce repetition in commands but still hold secrets in process context, so clearing or rotating them regularly limits exposure.
- Call a protected API endpoint by sending the bearer token in the Authorization header.
$ curl --silent --header "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://api.example.net/bearer/protected" { "authenticated": true, "token": "access_123" }The Authorization header must exactly match the expected format Authorization: Bearer <token> or the server may treat the request as anonymous.
- 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.net/bearer/protected" \ --verbose --silent ##### snipped ##### > GET /bearer/protected HTTP/1.1 > Host: api.example.net > User-Agent: curl/8.5.0 > Accept: */* > Authorization: Bearer access_123 ##### snipped #####Verbose output prints headers to the terminal and potentially to log files, which can expose tokens on shared systems.
- Store the Authorization header in a restricted curl configuration file for repeated local use.
$ echo 'header = "Authorization: Bearer access_123"' > .bearer_token $ chmod 600 .bearer_token $ ls -l .bearer_token -rw------- 1 root root 44 Jan 10 04:10 .bearer_token
World-readable configuration files allow other local users to replay the bearer token until it expires or is revoked.
- Use the configuration file when sending authenticated API requests.
$ curl --silent --config .bearer_token "https://api.example.net/bearer/protected" { "authenticated": true, "token": "access_123" }--config reads options and headers from the specified file so scripted calls remain shorter and consistent.
- Exchange a refresh token for a new access token when the original token expires.
$ curl --silent --request POST "https://api.example.net/oauth/token" \ --header "Content-Type: application/x-www-form-urlencoded" \ --data "grant_type=refresh_token&refresh_token=refresh-demo&client_id=demo-client&client_secret=demo-secret" { "access_token": "access_refreshed_789", "expires_in": 3600, "refresh_token": "refresh_456", "token_type": "Bearer" }Refreshing tokens on a schedule avoids authentication failures when the original access_token reaches its expires_in limit.
- 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.net/bearer/protected" 200HTTP status codes 200 or 201 typically indicate success, while 401 Unauthorized or 403 Forbidden suggest token issues or insufficient scope.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
