JSON Web Token authentication

Vector Search supports authenticated index endpoints using self-signed JSON Web Tokens (JWTs) . To control access to the index endpoint, it's configured to accept only signed JWTs issued by specifically authorized Google service accounts. This means only clients using those designated accounts can interact with the endpoint.

This page outlines the required steps for setting up an index endpoint with JSON Web Token (JWT) authentication and running queries against it.

Limitations

  • JWT authentication is supported only for private endpoints with VPC peering or Private Service Connect (PSC) .
  • JWT authentication is supported only for data plane RPC APIs (such as MatchService) that are invoked by using gRPC. The RPC examples in this page use the open source grpc_cli tool to send gRPC requests to the deployed index server.
  • Admin APIs for creation, deployment, and management of indexes are secured by using predefined IAM roles .

Creating and using a JWT to query an index

Follow these steps to create an index endpoint and query it with a self-signed JWT.

Create an index

Create a Vector Search index by following the instructions in Create an index .

Create a private endpoint

Create a private endpoint by following the instructions in one of the following documentation pages:

Create a service account and grant it the Service Account Token Creator IAM role.

  1. Enable the IAM Service Account Credentials API and create a service account:

     gcloud  
    services  
     enable 
      
    iamcredentials.googleapis.com  
    --project = 
     " PROJECT_ID 
    " 
    gcloud  
    iam  
    service-accounts  
    create  
     SERVICE_ACCOUNT_ID 
      
    --project = 
     " PROJECT_ID 
    " 
     
    

    Replace the following values:

    • PROJECT_ID : The project to create your service account in.
    • SERVICE_ACCOUNT_ID : The ID for the service account.

    Learn more about creating a service account .

  2. Use one of the following commands to grant the iam.serviceAccountTokenCreator IAM role to your service account:

    • The following command gives you permission to create JWTs by using the service account from a Compute Engine VM that has the service account attached to it:

       gcloud  
      iam  
      service-accounts  
      add-iam-policy-binding  
       \ 
        
       " SERVICE_ACCOUNT_ID 
      @ PROJECT_ID 
      .iam.gserviceaccount.com" 
        
       \ 
        
      --role  
       "roles/iam.serviceAccountTokenCreator" 
        
       \ 
        
      --member  
       "serviceAccount: SERVICE_ACCOUNT_ID 
      @ PROJECT_ID 
      .iam.gserviceaccount.com" 
        
       \ 
        
      --project  
       " PROJECT_ID 
      " 
       
      

      Replace the following values:

      • SERVICE_ACCOUNT_ID : The ID for the service account.
      • PROJECT_ID : The project to create your service account in.
    • The following command grants permission to create JWTs by using the service account from your own Google Account (on your workstation):

       gcloud  
      iam  
      service-accounts  
      add-iam-policy-binding  
       \ 
        
       " SERVICE_ACCOUNT_ID 
      @ PROJECT_ID 
      .iam.gserviceaccount.com" 
        
       \ 
        
      --role  
       "roles/iam.serviceAccountTokenCreator" 
        
       \ 
        
      --member  
       "user: EMAIL_ADDRESS 
      " 
        
       \ 
        
      --project  
       PROJECT_ID 
       
      

      Replace the following values:

      • SERVICE_ACCOUNT_ID : The ID for the service account.
      • PROJECT_ID : The project to create your service account in.
      • EMAIL_ADDRESS : Your email address.

Deploy the index to the endpoint with JWT auth config

  1. Deploy the index to the private endpoint as shown in the following example:

     gcloud  
    ai  
    index-endpoints  
    deploy-index  
     INDEX_ENDPOINT_ID 
      
     \ 
      
    --index = 
     INDEX_ID 
      
     \ 
      
    --deployed-index-id = 
     DEPLOYED_INDEX_ID 
      
     \ 
      
    --display-name = 
     DEPLOYED_INDEX_NAME 
      
     \ 
      
    --audiences = 
     AUDIENCES 
      
     \ 
      
    --allowed-issuers = 
     " SERVICE_ACCOUNT_ID 
    @ PROJECT_ID 
    .iam.gserviceaccount.com" 
      
     \ 
      
    --project = 
     PROJECT_ID 
      
     \ 
      
    --region = 
     LOCATION 
     
    

    Replace the following values:

    • INDEX_ENDPOINT_ID : The ID of the index endpoint.
    • INDEX_ID : The ID of the index.
    • DEPLOYED_INDEX_ID : A user specified string to uniquely identify the deployed index. It must start with a letter and contain only letters, numbers or underscores. See DeployedIndex.id for format guidelines.
    • DEPLOYED_INDEX_NAME : Display name of the deployed index.
    • AUDIENCES : A descriptive string that identifies the expected audience for your service, workload or app, for example, "123456-my-app" .
    • SERVICE_ACCOUNT_ID : The ID for the service account.
    • PROJECT_ID : Your Google Cloud project ID .
    • LOCATION : The region where you are using Vertex AI.

Query the index with a self-signed JWT

At a high level, the required steps are as follows:

  1. Create a JWT payload.
  2. Sign the token by using the service account created earlier.
  3. Query the index by using a gRPC call, passing the token in the authorization header.

Python

Create and Sign the JWT payload

This example uses the Python IAM API Credentials library's sign_jwt method to obtain a signed token. To learn more about how to install and use this library, see the IAM API Client Libraries documentation .

  from 
  
 google.cloud 
  
 import 
  iam_credentials 
 
_v1 from 
  
 datetime 
  
 import 
 datetime 
 , 
 timezone 
 import 
  
 json 
 def 
  
 sign_jwt 
 ( 
 issuer 
 : 
 str 
 , 
 audience 
 : 
 str 
 ): 
 client 
 = 
 iam_credentials_v1 
 . 
  IAMCredentialsClient 
 
 () 
 payload 
 = 
 { 
 'aud' 
 : 
 audience 
 , 
 'sub' 
 : 
 audience 
 , 
 'iss' 
 : 
 issuer 
 , 
 'iat' 
 : 
 int 
 ( 
 datetime 
 . 
 now 
 ( 
 timezone 
 . 
 utc 
 ) 
 . 
 timestamp 
 ()), 
 'exp' 
 : 
 int 
 ( 
 datetime 
 . 
 now 
 ( 
 timezone 
 . 
 utc 
 ) 
 . 
 timestamp 
 ()) 
 + 
 600 
 , 
 } 
 response 
 = 
 client 
 . 
  sign_jwt 
 
 ( 
 name 
 = 
 "projects/-/serviceAccounts/" 
 + 
 issuer 
 , 
 payload 
 = 
 json 
 . 
 dumps 
 ( 
 payload 
 )) 
 return 
 response 
 . 
 signed_jwt 
 sign_jwt 
 ( 
 " SERVICE_ACCOUNT_ID 
@ PROJECT_ID 
.iam.gserviceaccount.com" 
 , 
 " AUDIENCES 
" 
 ) 
 

Command-line

Create the JWT payload

Vector Search authentication accepts JWTs that are signed with a pre-authorized service account, for a predefined audience. The service account and audience must be specified by the caller when an index is deployed to a private endpoint. Once an index is deployed with these settings, all gRPC API requests to that endpoint are required to include an authorization header containing a JWT that's signed by the issuer (a service account) and targeted at the provided audience. The signed JWT is passed as a bearer token in the authorization header of the gRPC request. In addition to being signed by the service account, the JWT must include the following claims:

  • The iss (allowed issuer) claim should be the service account email address, for example:

      "iss" 
     : 
      
     " SERVICE_ACCOUNT_ID 
    @ PROJECT_ID 
    .iam.gserviceaccount.com" 
     
    
  • The aud (audience) and sub (subject) claims should both be set to the same value. This is a descriptive string that identifies the expected audience for your service, workload or app, for example:

      "aud" 
     : 
      
     "123456-my-app" 
     , 
     "sub" 
     : 
      
     "123456-my-app" 
     
    

    This value must match the --audiences argument that was passed at index deployment time.

  • The iat (issued at) claim should be set to the time the token is issued. The exp (expiration time) claim should be set to a short time later (about an hour). These values are expressed in Unix epoch time, for example:

      "iat" 
     : 
      
     1698966927 
     , 
      
     // unix time since epoch eg via date +%s 
     "exp" 
     : 
      
     1698967527 
      
     // iat + a few mins (eg 600 seconds) 
     
    

The following example shows these claims in a single JWT payload:

  { 
  
 "iss" 
 : 
  
 " SERVICE_ACCOUNT_ID 
@ PROJECT_ID 
.iam.gserviceaccount.com" 
 , 
  
 "aud" 
 : 
  
 "123456-my-app" 
 , 
  
 "sub" 
 : 
  
 "123456-my-app" 
 , 
  
 "iat" 
 : 
  
 1698956084 
 , 
  
 "exp" 
 : 
  
 1698960084 
 } 
 

The JWT payload is signed by using the service account specified in the iss claim.

Create the JWT

  1. Make sure that you (the caller) can use the roles/iam.serviceAccountTokenCreator role on the service account.

  2. Create a JSON file named jwt_in.json that contains the raw JWT:

      SA 
     = 
     "serviceAccount: SERVICE_ACCOUNT_ID 
    @ PROJECT_ID 
    .iam.gserviceaccount.com" 
    cat << 
    EOF > 
    jwt_in.json { 
      
     "aud" 
    :  
     " AUDIENCES 
    " 
    ,  
     "sub" 
    :  
     " AUDIENCES 
    " 
    ,  
     "iss" 
    :  
     " 
     ${ 
     SA 
     } 
     " 
    ,  
     "iat" 
    :  
     $( 
    date  
    +%s ) 
    ,  
     "exp" 
    :  
     $( 
    expr  
     $( 
    date  
    +%s ) 
      
    +  
     600 
     ) 
     } 
    EOF 
    

    Replace the following values:

    • SERVICE_ACCOUNT_ID : The ID for the service account.
    • PROJECT_ID : Your Google Cloud project ID .
    • AUDIENCES : A descriptive string that identifies the expected audience for your service, workload or app, for example, "123456-my-app" .

Sign the JWT (REST API)

  1. Using the jq tool , create the curl request payload by encoding the JWT into a string:

     cat  
    jwt_in.json  
     | 
      
    jq  
    -Rsa  
    >request.json 
    
  2. Sign the token by passing the request payload to the signJwt REST API method.

      SA 
     = 
     "serviceAccount: SERVICE_ACCOUNT_ID 
    @ PROJECT_ID 
    .iam.gserviceaccount.com" 
    curl  
    -X  
    POST  
     \ 
      
    -H  
     "Authorization: Bearer 
     $( 
    gcloud  
    auth  
    print-access-token ) 
     " 
      
     \ 
      
    -H  
     "Content-Type: application/json; charset=utf-8" 
      
     \ 
      
    -d  
    @request.json  
     \ 
      
     "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/ 
     $SA 
     :signJwt" 
     
    

    Replace the following values:

    • SERVICE_ACCOUNT_ID : The ID for the service account.
    • PROJECT_ID : Your Google Cloud project ID .

    Store the returned signedJwt value into an environment variable called signedJwt .

Sign the JWT (gcloud CLI)

Alternatively, you can sign the JWT by passing the jwt_in.json file directly to the gcloud CLI sign-jwt method.

 gcloud  
iam  
service-accounts  
sign-jwt  
jwt_in.json  
jwt_out  
 \ 
  
--iam-account = 
 SERVICE_ACCOUNT_ID 
@ PROJECT_ID 
.iam.gserviceaccount.com 

Replace the following values:

  • SERVICE_ACCOUNT_ID : The ID for the service account.
  • PROJECT_ID : Your Google Cloud project ID .

The signed JWT is returned in the jwt_out output file. Store it into an environment variable called signedJwt .

Send the signed JWT to the index endpoint

Python

To learn how to install or update the Vertex AI SDK for Python, see Install the Vertex AI SDK for Python . For more information, see the Python API reference documentation .

  def 
  
 vector_search_match_jwt 
 ( 
  
 project 
 : 
  
 str 
 , 
  
 location 
 : 
  
 str 
 , 
  
 index_endpoint_name 
 : 
  
 str 
 , 
  
 deployed_index_id 
 : 
  
 str 
 , 
  
 queries 
 : 
  
 List 
 [ 
 List[float 
 ] 
 ] 
 , 
  
 num_neighbors 
 : 
  
 int 
 , 
  
 signed_jwt 
 : 
  
 str 
 , 
 ) 
  
 - 
>  
 List 
 [ 
 List[aiplatform.matching_engine.matching_engine_index_endpoint.MatchNeighbor 
 ] 
 ]: 
  
 """Query the vector search index. 
 Args: 
 project (str): Required. Project ID 
 location (str): Required. The region name 
 index_endpoint_name (str): Required. Index endpoint to run the query 
 against. The endpoint must be a private endpoint. 
 deployed_index_id (str): Required. The ID of the DeployedIndex to run 
 the queries against. 
 queries (List[List[float]]): Required. A list of queries. Each query is 
 a list of floats, representing a single embedding. 
 num_neighbors (int): Required. The number of neighbors to return. 
 signed_jwt (str): Required. The signed JWT token for the private 
 endpoint. The endpoint must be configured to accept tokens from JWT's 
 issuer and encoded audience. 
 Returns: 
 List[List[aiplatform.matching_engine.matching_engine_index_endpoint.MatchNeighbor]] - A list of nearest neighbors for each query. 
 """ 
  
 # 
  
 Initialize 
  
 the 
  
 Vertex 
  
 AI 
  
 client 
  
 aiplatform 
 . 
 init 
 ( 
 project 
 = 
 project 
 , 
  
 location 
 = 
 location 
 ) 
  
 # 
  
 Create 
  
 the 
  
 index 
  
 endpoint 
  
 instance 
  
 from 
  
 an 
  
 existing 
  
 endpoint 
 . 
  
 my_index_endpoint 
  
 = 
  
 aiplatform 
 . 
 MatchingEngineIndexEndpoint 
 ( 
  
 index_endpoint_name 
 = 
 index_endpoint_name 
  
 ) 
  
 # 
  
 Query 
  
 the 
  
 index 
  
 endpoint 
  
 for 
  
 matches 
 . 
  
 resp 
  
 = 
  
 my_index_endpoint 
 . 
 match 
 ( 
  
 deployed_index_id 
 = 
 deployed_index_id 
 , 
  
 queries 
 = 
 queries 
 , 
  
 num_neighbors 
 = 
 num_neighbors 
 , 
  
 signed_jwt 
 = 
 signed_jwt 
 , 
  
 ) 
  
 return 
  
 resp 
 

Command-line

From a Compute Engine VM in the same VPC network, call the MatchService gRPC endpoint, passing the signedJwt token in the authorization header, as shown in the following example:

 ./grpc_cli  
call  
 ${ 
 TARGET_IP 
 } 
:10000  
google.cloud.aiplatform.container.v1.MatchService.Match  
 \ 
  
 '{deployed_index_id: "${DEPLOYED_INDEX_ID}", float_val: [-0.1,..]}' 
  
 \ 
  
--metadata  
 "authorization: Bearer 
 $signedJwt 
 " 
 

To run this command, you'll need the following environment variables to be set:

  • TARGET_IP is the IP address for your deployed index server. To learn how to retrieve this value, see Query indexes to get nearest neighbors .
  • DEPLOYED_INDEX_ID : A user specified string to uniquely identify the deployed index. It must start with a letter and contain only letters, numbers or underscores. See DeployedIndex.id for format guidelines.

signedJwt is the environment variable containing your signed JWT.

Troubleshooting

The following table lists some common gRPC error messages.

gRPC Error Message Reason
Authorization header not found for index ' INDEX_ID ' The gRPC metadata doesn't contain an authorization header
JWT is invalid format The token is malformed and can't be parsed correctly
JWT authentication failed The token is expired or isn't signed by the correct service account
JWT issuer should be in the allowed issuers list The token iss isn't in auth_config allowed issuers
Permission check fail for index ' INDEX_ID ' The token aud or sub claim isn't in auth_config audiences

What's next

Create a Mobile Website
View Site in Mobile | Classic
Share by: