API authorization

Implementing the OAuth2 protocol in the API

For authentication and authorization, the API uses the OAuth2 protocol, from the specification of which two standard schemes (flow) are implemented: Client Credentials Grant and Authorization Code Grant, and one non-standard — Agency Client Credentials Grant.

Client Credentials Grant used for work with your own account data through the API.

Agency Client Credentials Grant it is used to work with data of own clients of agencies/managers.

Authorization Code Grant used to access data to third-party myTarget accounts.

The first two schemes are available to each API client, access to the Authorization Code Grant scheme is granted only if the conditions are met.

Instructions for accessing the API

Using any of these methods, you will get an Access Token object containing the access_token and refresh_token keys. Each API request must be signed with the access_token key:

GET /api/v2/campaigns.json HTTP/1.1
Host: target.my.com
Authorization: Bearer {access_token}
Note that access to account data is possible only with the token received for this account. This means that you can not, for example, view the campaigns of the client of the agency, signing the request with the token of the agency itself. Learn more about account types and the authorization process in the advanced authorization instructions.

Client Credentials Grant

To get the access token, you need to send a request:

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}
In case of successful execution, the response will look like the following:

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
    
{
  "access_token": "{access_token}",
  "token_type": "bearer",
  "scope": "{scope}",
  "expires_in": "86400",
  "refresh_token": "{refresh_token}"
}

Agency Client Credentials Grant

This OAuth2 Protocol scheme is not standard. It was implemented to enable agencies and managers to create access tokens for their clients without confirmation from the client. The scheme is very similar to the standard Client Credentials Grant, except that an additional parameter "agency_client_name" or "agency_client_id" must be passed in the request (username or user id from the request AgencyClients or ManagerClients):

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
    
grant_type=agency_client_credentials&client_id={client_id}&client_secret={client_secret}&{agency_client_name|agency_client_id}={client_username|client_user_id}

Authorization Code Grant

This OAuth2 Protocol scheme allows you to obtain a myTarget third-party user token. When creating access to the Authorization Code Grant scheme, the address "redirect_uri" must be specified - myTarget will redirect users to it after they give access (or refuse) to their API client account.

The algorithm for getting access:

The API client redirects the user to a special page /oauth2/authorize by specifying the parameters "response_type" (with the value "code"), "state" (a client-side generated token used to prevent CSRF - may contain an arbitrary character set), its "client_id" and the access rights list "scope":

GET /oauth2/authorize?response_type=code&client_id={client_id}&state={state}&scope={scopes} HTTP/1.1
Host: target.my.com
The user on the page agrees to give access and the service redirects it to the address specified by the parameter "redirect_uri" when registering the client, passing the parameters "code" (a special token with a lifetime of one hour) and "state" (the same value that was passed in the original request):

GET {redirect_uri:path}?code={code}&state={state}&user_id={user_id} HTTP/1.1
Host: <redirect_uri:host>
The response includes the user_id parameter, which contains the identifier of the user granting access.

In the same way, get user_id by code:

POST /api/v2/oauth2/code_info.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
code={code}&client_id={client_id}&client_secret={client_secret}
An example of a successful response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
 
{
 "user":
 {
    "id": 100500,
    "username": "mytarget@mail.ru",
    "types": ["advert", "agency_client"]
 }
} 
If your application already has a token for this user, you can continue to use the existing one to avoid exceeding the limit of tokens and not duplicate tokens.
After receiving the "code" parameter, the client can request "access_token" for further work with the API on behalf of the user. To do this, send a request to /api/v2/oauth2/token.json, passing the parameters "grant_type" (with the value "authorization_code"), "code "(obtained by reverse redirecting to "redirect_uri" token):

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
    
grant_type=authorization_code&code={code}&client_id={client_id}
Answer:

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
{
  "access_token": "{access_token}",
  "token_type": "Bearer",
  "scope": ["{scope1}", "{scope2}"],
  "expires_in": 86400,
  "refresh_token": "{refresh_token}"
}
The resulting access token is used to authenticate requests sent to the API on behalf of the user:

GET /api/v2/campaigns.json HTTP/1.1
Host: target.my.com
Authorization: Bearer {access_token}
To receive tokens from the clients of the Agency or Manager that granted access, you must use the extended Agency Client Credentials scheme. To do this, in addition to the agency_client_name parameter and others, you must specify the appropriate Agency token in the access_token parameter:

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
    
grant_type=agency_client_credentials&client_id={client_id}&client_secret={client_secret}&agency_client_name={client_username}&access_token={agency_access_token}
If the request is successful, the answer will contain an access token to perform operations on behalf of the Agency client or Manager.

Scopes — access right

Access rights determine what actions the API client can take with the data of the account that granted access. The required permissions are specified separated by commas in the "scope" parameter of the user access request in the Authorization Code Grant scheme. Depending on the type of user, the requested access rights are divided into three groups.

For the average user-advertiser:
  • read_ads — reading statistics and campaigns;
  • read_payments — read cash transactions and balance;
  • create_ads — create and edit campaign settings, banners, audiences (rates, status, targeting, etc.).

For the user-agency and user-representative:
  • create_clients — creating new clients;
  • read_clients — view clients and transactions on their behalf;
  • create_agency_payments — transfers of funds to and from client accounts.

For user-manager:
  • read_manager_clients — read customers and transactions on their behalf;
  • edit_manager_clients — changing client settings;
  • read_payments — read cash transactions and balance.

In one request, the rights of different groups can be specified. myTarget determines the account type of the current user and opens only the appropriate rights. Moreover, if the request, for example, lists all the rights, and the user is an Agency, he will be asked to choose which account he wants to give access to-to the Agency with Agency rights, any of the management with management or one of the client with access rights to client data.

Working with tokens

Limit on the number of tokens

No more than 5 tokens can exist at a time for each clientId - user bundle, regardless of the token status. If the same account is connected to two different applications, each of the applications will be able to issue 5 tokens for this account. The limit is fixed and cannot be increased in any case.

Non-perpetual tokens are automatically deleted after a month of inactivity (specified in the "expires_in" field).

When the limit is reached, an error with HTTP code 403 will be returned in response to an try to get a new token.

In order to avoid such errors, it is necessary to update the issued tokens correctly and not to create redundant copies of them.

Removing tokens

When the limit on the number of tokens is reached, you can independently delete all the tokens of a particular user. To do this, use a request of the form:

POST /api/v2/oauth2/token/delete.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
    
client_id={client_id}&client_secret={client_secret}&{username|user_id}={username|user_id}
where "username" is the login of the user (user_id is the user ID) for which tokens should be deleted. If the "username" or "user_id" parameter is not passed, the tokens of the account for which the API access was granted will be deleted.

Access token validity period

Each received access token is valid for one day by default. This is indicated by the "expires_in" property in the response to the access token request. The limited lifetime allows you to more reliably protect the value of "access_token". Even with the value of one "access_token", the attacker will not be able to make requests with it after the expiration or after the first token update.

A less secure way is "perpetual" access tokens. To get "access_token" without expiration limit, you need to add the GET parameter "permanent=true" to the token creation or update request. For example:

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&permanent=true

Update access token

The Access Token object also contains the "refresh_token" key — a special token to update the access_token key and extend the lifetime of the object. The Refreshing an Access Token scheme in the OAuth2 Protocol is responsible for this.

A request to refresh the access token:

POST /api/v2/oauth2/token.json HTTP/1.1
Host: target.my.com
Content-Type: application/x-www-form-urlencoded
    
grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}
Example answer:

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
    
{
  "access_token": "{new_access_token}",
  "token_type": "bearer",
  "scope": "{scope}",
  "expires_in": "86400",
  "refresh_token": "{refresh_token}"
}
It is important to note that updating the token does not create a new instance: the value of "access_token" changes, the old value of the key stops working. This can lead to problems when working with the API in multiple threads: two threads can simultaneously detect that the token has expired and send an update request. The request that comes first will update the token and start using it, while the second thread will update the token again and the first thread will try to use an already nonexistent token.

One solution to this problem is to catch an error about a nonexistent token in the first thread and retrieve the token anew from a thread-shared repository – for example, a database where each thread writes the token after an update. You should also take into account that the record in the store can also be competitive, and use, for example, locks.

Another solution to this problem might be to enable the "refresh_token" update option on each "access_token" update. Then the first thread will update both "access_token" and "refresh_token", and in the second you need to handle the error about the unknown "refresh_token" and re-read "access_token" from the repository. But when updating "refresh_token" you must keep its most recent value, otherwise you will no longer be able to update "access_token", and will have to write out a new one. This OAuth client option can now only be enabled on a support request (ads_api@vk.team).

Another option is to proactively update all expiring tokens. It is that you need to regularly check if you have any tokens expiring, for example, in the next half hour, and update them in the background process. But if you combine it with real-time updates in workflows, you still have to handle errors because of possible conflicts.

Errors when using incorrect tokens

When you call any API method, various errors related to an incorrect value or state "access_token"may be returned.

Such errors have a 401 code and a common structure:

{"code": "Error code", "message": "Error description"}
The answer will also contain a header

WWW-Authenticate: Bearer realm="api", error="Error code", error_description="Error description"
Typical errors:
Error
Reason
Recommendations
{"code": "invalid_token", "message": "Unknown access token"}
The specified "access_token" does not exist. The error is also possible if the token has not been updated for a month and, accordingly, has been automatically deleted.
Write a new token for this user and repeat the request using this token.
{"code": "expired_token", "message": "Access token is expired"}
"access_token" has expired, but it hasn't been deleted yet.
Update "access_token" using the "refresh_token" method.
{"code": "invalid_client", "message": "Client is blocked"}
OAuth2 client blocked. The OAuth2 client (in fact, API access) can be blocked in case of violations of API usage rules and similar cases.
Please contact customer service.
{"code": "invalid_user", "message": "User is blocked"}
The user for whom the token was issued is blocked.
Send a request with another user's token.
{"code": "revoked_token", "message": "Access token has been revoked"}
The user who previously granted your app access to their account has revoked that access.
Request the user to re-grant access. It is also recommended that you stop any requests on behalf of this user until they re-grant access.
{"code": "revoked_token", "message": "Access token has been revoked"}
The user who received the token through the Agency Client Credentials scheme (using the Agency or Manager token) has ceased to be a client of the Agency or to be connected to the Manager.
{ "error": "empty_request_body", "error_description": "Request body is empty. form-urlencoded POST-request required" }
Empty POST request
Empty POST request. Make sure that the parameters are passed in the body of the POST request, and not in the GET parameters.
{ "error": "empty_grant_type", "error_description": "grant_type parameter must be non-empty string" }
Empty grant_type
The grant_type value was omitted
{ "error": "unsupported_grant_type", "error_description": "Unsupported value "%s" of "grant_type" paramenter" }
The grant_type parameter is not from the following list:
authorization_code,
client_credentials,
refresh_token,
agency_client_credentials
{"error": "invalid_request", "error_description": "Unknown agency client"}
User does not have a client with the specified in the request agency_client_name/id
Was this article helpful?