Bearer authentication in Ktor Client
Bearer authentication uses security tokens called bearer tokens. These tokens are commonly used in OAuth 2.0 flows to authorize users through external providers, such as Google, Facebook, and X.
You can learn more about the OAuth process in the OAuth authorization flow section of the Ktor server documentation.
Add dependencies
To enable authentication, include the ktor-client-auth artifact in the build script:
Configure bearer authentication
A Ktor client allows you to send a token in the Authorization header using the Bearer scheme. You can also define logic that refreshes tokens when they expire.
To configure bearer authentication, install the Auth plugin and configure the bearer provider:
Load tokens
Use the loadTokens {} callback to provide the initial access and refresh tokens. Typically, this callback loads cached tokens from local storage and returns them as a BearerTokens instance.
In this example, the client sends the abc123 access token in the Authorization header:
Refresh tokens
Use the refreshTokens {} callback to define how the client obtains new tokens when the current access token becomes invalid:
The refresh process works as follows:
The client makes a request to a protected resource using an invalid access token.
The resource server returns a
401 Unauthorizedresponse.The client automatically invokes the
refreshTokens {}callback to obtain new tokens.The client retries the request to a protected resource using the new token.
When multiple requests fail with 401 Unauthorized at the same time, the client performs the token refresh only once. The first request that receives the 401 response triggers the refreshTokens {} callback. Other requests wait for the refresh operation to complete and are then retried with the new token.
Send credentials without waiting for 401
By default, the client sends credentials only after receiving a 401 Unauthorized response.
You can override this behavior using the sendWithoutRequest {} callback function. This callback determines whether the client should attach credentials before sending the request.
For example, the following configuration always sends the token when accessing Google APIs:
Cache tokens
Use the cacheTokens property to control whether bearer tokens are cached between requests.
If caching is disabled, the client calls the loadTokens {} function for every request:
Disabling caching can be useful when tokens change frequently.
Example: Using Bearer authentication to access Google API
This example demonstrates how to use bearer authentication with Google APIs, which use the OAuth 2.0 protocol for authentication and authorization.
The example application client-auth-oauth-google retrieves the user's Google profile information.
Obtain client credentials
To access Google APIs, you first need to obtain OAuth client credentials:
Create or sign in to a Google account.
Open the Google Cloud Console
Create an
OAuth client IDwith theAndroidapplication type. You will use this client ID to obtain an authorization grant.
OAuth authorization flow
The OAuth authorization flow consists of the following steps:
The client sends an authorization request to the resource owner.
The resource owner returns an authorization code.
The client sends the authorization code to the authorization server.
The authorization server returns access and refresh tokens.
The client sends a request to the resource server using the access token.
The resource server returns the protected resource.
After the access token expires, the client sends a request with the expired token.
The resource server responds with 401 Unauthorized.
The client sends the refresh token to the authorization server.
The authorization server returns new access and refresh tokens.
The client sends a new request to the resource server using the new access token.
The resource server returns the protected resource.
The following sections explain how the Ktor client implements each step.
Authorization request
First, construct the authorization URL used to request the necessary permissions. This is done by appending the required query parameters:
client_id: the OAuth client ID used to access the Google APIs.scope: the permissions requested by the application. In this case, it is information about a user's profile.response_type: a grant type used to get an access token. Set to"code"to obtain an authorization code.redirect_uri: thehttp://127.0.0.1:8080value indicates that the Loopback IP address flow is used to get the authorization code.access_type: set toofflineso that the application can refresh access tokens when the user is not present at the browser.
Authorization grant (code)
After granting access, the browser returns an authorization code. Copy the code and store it in a variable:
Exchange authorization code for tokens
Next, exchange the authorization code for tokens. To do this, create a client and install the ContentNegotiation plugin with the JSON serializer:
This serializer is required to deserialize tokens received from the Google OAuth token endpoint.
Using the created client, pass the authorization code and other necessary options to the token endpoint as form parameters:
The token endpoint returns a JSON response that the client deserializes into a TokenInfo instance. The TokenInfo class looks as follows:
Store tokens
Once the tokens are received, store them so they can be supplied to the loadTokens {} and refreshTokens {} callbacks. In this example, the storage is a mutable list of BearerTokens:
Send a request with a valid token
Now that valid tokens are available, the client can make a request to the protected Google API and retrieve user information.
Before doing that, configure the client to use bearer authentication:
The following settings are specified:
The
loadTokenscallback retrieves tokens from storage.The
sendWithoutRequest {}callback sends the access token without waiting for the401 Unauthorizedresponse when calling the Google API.
With this client, you can now make a request to the protected resource:
Access the protected resource
The resource server returns information about a user in a JSON format. You can deserialize the response into the UserInfo class instance and display a personal greeting:
The UserInfo class looks as follows:
Request with expired token
At some point, the client repeats the request from Step 5, but with an expired access token.
401 Unauthorized response
When the token is no longer valid, the resource server returns a 401 Unauthorized response. The client then invokes the refreshTokens {} callback, which is responsible for obtaining new tokens.
Refresh the access token
To obtain a new access token, configure the refreshTokens {} callback to make another request to the token endpoint. This time, use the refresh_token grant type instead of authorization_code:
The refreshTokens {} callback uses RefreshTokensParams as a receiver and allows you to access the following settings:
The
clientinstance, which can be used to submit form parameters.The
oldTokensproperty is used to access the refresh token and send it to the token endpoint.The
.markAsRefreshTokenRequest()function exposed byHttpRequestBuildermarks the request for refreshing auth tokens, resulting in a special handling of it.
Save refreshed tokens
After receiving new tokens, save them in the token storage. With this, the refreshTokens {} callback looks as follows:
Request with new token
With the refreshed access token stored, the next request to the protected resource should succeed:
Handle API errors
Given that the 401 Unauthorized response returns JSON data with error details, update the example to read error responses as an ErrorInfo object:
The ErrorInfo class is defined as follows: