> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basic.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# ⚡️ Quickstart

> Integrate Basic into your project using REST APIs

<Info>
  First, check if there's an existing Basic SDK for your technology stack and use it instead for a better dev experience!
</Info>

# Summary

There are two main steps to integrating Basic into your app: implement Basic Auth, then call the database APIs with the user's access token.

<CardGroup>
  <Card title="Auth APIs guide" href="/basic-restapi/basic-api#basic-auth-apis-guide">
    Implement signup / login flows for your app's users
  </Card>

  <Card title="Database APIs guide" href="/basic-restapi/basic-api#basic-database-apis-guide">
    Write and display data safely in your app
  </Card>
</CardGroup>

# Basic Auth APIs guide

Basic uses OAuth 2.0 for authentication. For more details, read about [Basic Auth](/readings/auth-basic#introduction-to-oauth-2-0).

In this guide, you will:

1. Use "redirect to sign in" endpoint to redirect users to account creation / login flow
2. Extract code from URL
3. Use "get auth token" endpoint with extracted code
4. Store auth token object for future API calls

<Steps>
  <Step title="Use &#x22;redirect to sign in&#x22; endpoint">
    Create a button that redirects the user to the Basic Auth page, with the following required parameters (more info on [required parameters](/readings/auth-basic#required-parameters)):

    * `client_id='YOUR_CLIENT_ID'`
    * `redirect_uri='YOUR_REDIRECT_URI'`
    * `response_type=code`
    * `scope=profile`
    * `state='YOUR_STATE'`

    Redirect URL template: `https://api.basic.tech/auth/authorize?response_type=code&redirect_uri=YOUR_REDIRECT_URI&scope=profile&state=YOUR_STATE&client_id=YOUR_CLIENT_ID`

    <Note>
      Replace `YOUR_CLIENT_ID`, `YOUR_REDIRECT_URI`, and `YOUR_STATE` with your own values. `scope` must be a space-separated list (for example `profile` alone, or `profile` plus datastore scopes your app needs). The live contract matches the [OpenAPI spec](/api-reference/auth/redirect-to-sign-in) (`GET /auth/authorize`).
    </Note>

    <Note>
      **PKCE (recommended):** You may include `code_challenge` and `code_challenge_method=S256` on the authorize request and the matching `code_verifier` when exchanging the code at `/auth/token`. See [Basic Auth](/readings/auth-basic) for the full OAuth flow.
    </Note>

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request GET \
          --url 'https://api.basic.tech/auth/authorize?response_type=code&redirect_uri='YOUR_REDIRECT_URI'&scope=profile&state='YOUR_STATE'&client_id='YOUR_CLIENT_ID''
      ```

      ```python Python theme={null}
      import requests

      url = "https://api.basic.tech/auth/authorize"

      querystring = {"response_type":"code","client_id":"YOUR_CLIENT_ID","redirect_uri":"YOUR_REDIRECT_URI","scope":"profile","state":"YOUR_STATE"}

      response = requests.request("GET", url, params=querystring)

      print(response.text)
      ```

      ```javascript JavaScript theme={null}
      const options = {method: 'GET'};

      fetch('https://api.basic.tech/auth/authorize?response_type=code&client_id='YOUR_CLIENT_ID'&redirect_uri='YOUR_REDIRECT_URI'&scope=profile&state='YOUR_STATE'', options)
      .then(response => response.json())
      .then(response => console.log(response))
      .catch(err => console.error(err));
      ```

      ```php PHP theme={null}
      <?php

      $curl = curl_init();

      curl_setopt_array($curl, [
          CURLOPT_URL => "https://api.basic.tech/auth/authorize?response_type=code&client_id='YOUR_CLIENT_ID'&redirect_uri='YOUR_REDIRECT_URI'&scope=profile&state='YOUR_STATE'",
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_ENCODING => "",
          CURLOPT_MAXREDIRS => 10,
          CURLOPT_TIMEOUT => 30,
          CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
          CURLOPT_CUSTOMREQUEST => "GET",
      ]);

      $response = curl_exec($curl);
      $err = curl_error($curl);

      curl_close($curl);

      if ($err) {
          echo "cURL Error #:" . $err;
      } else {
          echo $response;
      }
      ```

      ```go Go theme={null}
      package main

      import (
          "fmt"
          "net/http"
          "io/ioutil"
      )

      func main() {

          url := "https://api.basic.tech/auth/authorize?response_type=code&client_id='YOUR_CLIENT_ID'&redirect_uri='YOUR_REDIRECT_URI'&scope=profile&state='YOUR_STATE'"

          req, _ := http.NewRequest("GET", url, nil)

          res, _ := http.DefaultClient.Do(req)

          defer res.Body.Close()
          body, _ := ioutil.ReadAll(res.Body)

          fmt.Println(res)
          fmt.Println(string(body))

      }
      ```

      ```java Java theme={null}
      HttpResponse<String> response = Unirest.get("https://api.basic.tech/auth/authorize?response_type=code&client_id='YOUR_CLIENT_ID'&redirect_uri='YOUR_REDIRECT_URI'&scope=profile&state='YOUR_STATE'")
      .asString();
      ```
    </CodeGroup>
  </Step>

  <Step title="Extract code from URL">
    The authorization code will be in the URL as a `code` query parameter.
    For example:
    `https://your-app.com/callback?code=1234567890`.

    You need to extract the code from the URL and use it in the next step.

    <CodeGroup>
      ```bash cURL theme={null}
      # Assuming the URL is stored in a variable
      URL="https://your-app.com/callback?code=1234567890"
      CODE=$(echo $URL | grep -o 'code=[^&]*' | cut -d'=' -f2)
      echo $CODE
      ```

      ```python Python theme={null}
      from urllib.parse import urlparse, parse_qs

      # Example URL
      url = "https://your-app.com/callback?code=1234567890"

      # Parse the URL and extract the code parameter
      parsed_url = urlparse(url)
      code = parse_qs(parsed_url.query)['code'][0]

      print(code)
      ```

      ```javascript JavaScript theme={null}
      // Example URL
      const url = "https://your-app.com/callback?code=1234567890";

      // Extract the code parameter
      const urlParams = new URLSearchParams(window.location.search);
      const code = urlParams.get('code');

      console.log(code);
      ```

      ```php PHP theme={null}
      <?php
      // Example URL
      $url = "https://your-app.com/callback?code=1234567890";

      // Parse the URL and extract the code parameter
      $query = parse_url($url, PHP_URL_QUERY);
      parse_str($query, $params);
      $code = $params['code'];

      echo $code;
      ?>
      ```

      ```go Go theme={null}
      package main

      import (
          "fmt"
          "net/url"
      )

      func main() {
          // Example URL
          rawURL := "https://your-app.com/callback?code=1234567890"
          
          // Parse the URL and extract the code parameter
          parsedURL, _ := url.Parse(rawURL)
          code := parsedURL.Query().Get("code")
          
          fmt.Println(code)
      }
      ```

      ```java Java theme={null}
      import java.net.URI;
      import java.net.URLDecoder;
      import java.nio.charset.StandardCharsets;
      import java.util.HashMap;
      import java.util.Map;

      public class Main {
          public static void main(String[] args) {
              // Example URL
              String url = "https://your-app.com/callback?code=1234567890";
              
              // Parse the URL and extract the code parameter
              String query = URI.create(url).getQuery();
              Map<String, String> params = new HashMap<>();
              for (String param : query.split("&")) {
                  String[] pair = param.split("=");
                  params.put(pair[0], URLDecoder.decode(pair[1], StandardCharsets.UTF_8));
              }
              String code = params.get("code");
              
              System.out.println(code);
          }
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Use &#x22;get auth token&#x22; endpoint with extracted code">
    Make a post request to `/auth/token` with the authorization code in the body. The response will be a JSON object with the access token and a refresh code.

    Token URL template:
    `https://api.basic.tech/auth/token`

    <Note>
      Make sure to replace `YOUR_CODE` with your own values
    </Note>

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
          --url 'https://api.basic.tech/auth/token' \
          --header 'Content-Type: application/json' \
          --data '{"code":"YOUR_CODE"}'
      ```

      ```python Python theme={null}
      import requests

      url = "https://api.basic.tech/auth/token"

      payload = {"code": "YOUR_CODE"}
      headers = {"Content-Type": "application/json"}

      response = requests.request("POST", url, json=payload, headers=headers)

      print(response.text)
      ```

      ```javascript JavaScript theme={null}
      const options = {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({code: 'YOUR_CODE'})
      };

      fetch('https://api.basic.tech/auth/token', options)
      .then(response => response.json())
      .then(response => console.log(response))
      ```

      ```php PHP theme={null}
      <?php

      $curl = curl_init();

      curl_setopt_array($curl, [
          CURLOPT_URL => "https://api.basic.tech/auth/token",
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_ENCODING => "",
          CURLOPT_MAXREDIRS => 10,
          CURLOPT_TIMEOUT => 30,
          CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
          CURLOPT_CUSTOMREQUEST => "POST",
          CURLOPT_POSTFIELDS => "{\n  \"code\": \"YOUR_CODE\"\n}",
          CURLOPT_HTTPHEADER => [
              "Content-Type: application/json"
          ],
      ]);

      $response = curl_exec($curl);
      $err = curl_error($curl);

      curl_close($curl);

      if ($err) {
          echo "cURL Error #:" . $err;
      } else {
      echo $response;
      }
      ```

      ```go Go theme={null}
      package main

      import (
          "fmt"
          "strings"
          "net/http"
          "io/ioutil"
      )

      func main() {

          url := "https://api.basic.tech/auth/token"

          payload := strings.NewReader("{\n  \"code\": \"YOUR_CODE\"\n}")

          req, _ := http.NewRequest("POST", url, payload)

          req.Header.Add("Content-Type", "application/json")

          res, _ := http.DefaultClient.Do(req)

          defer res.Body.Close()
          body, _ := ioutil.ReadAll(res.Body)

          fmt.Println(res)
          fmt.Println(string(body))

      }
      ```

      ```java Java theme={null}
      HttpResponse<String> response = Unirest.post("https://api.basic.tech/auth/token")
      .header("Content-Type", "application/json")
      .body("{\n  \"code\": \"YOUR_CODE\"\n}")
      .asString();
      ```
    </CodeGroup>
  </Step>

  <Step title="Store auth token object for future API calls">
    The response from the token endpoint will look like this:

    ```json theme={null}
    {
      "access_token": "<string>",
      "token_type": "<string>",
      "expires_in": 123,
      "refresh_token": "<string>"
    }
    ```
  </Step>
</Steps>

# Basic database APIs guide

The [database APIs](/api-reference/project-users/create-item) are easy to use.

Make sure to check the validity of the `access_token`, and pass it in the Header of your API call.

If the `access_token` is expired, you'd repeat step 3 of the [Auth APIs guide](/basic-restapi/basic-api#basic-auth-apis-guide) but using the `refresh_token` instead of the extracted code. This will return you a fresh new `access_token`.

Here's how to validate and use the access token in different programming languages:

<CodeGroup>
  ```bash cURL theme={null}
  # Note: For bash, you'll need to use a JWT decoding tool like jq or jwt-cli
  # Example using jwt-cli:
  # if jwt decode YOUR_ACCESS_TOKEN | jq '.exp > now' | grep -q "true"; then
  #   # Token is valid, proceed with API calls
  curl --request GET \
   --url 'https://api.basic.tech/your-endpoint' \
   --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  # else
  #   # Token is expired, refresh it
  curl --request POST \
   --url 'https://api.basic.tech/auth/token' \
   --header 'Content-Type: application/json' \
   --data '{"refresh_token":"YOUR_REFRESH_TOKEN"}'
  ```

  ```python Python theme={null}
  import jwt
  import time
  import requests

  def refresh_token(refresh_token):
      response = requests.post(
          'https://api.basic.tech/auth/token',
          json={'refresh_token': refresh_token},
          headers={'Content-Type': 'application/json'}
      )
      return response.json()

  def is_token_valid(access_token):
      try:
          # Decode the token without verification
          decoded = jwt.decode(access_token, options={"verify_signature": False})
          # Check if token is expired
          return decoded['exp'] > time.time()
      except:
          return False

  # Example usage
  if is_token_valid(access_token):
      # Token is valid, proceed with API calls
      headers = {'Authorization': f'Bearer {access_token}'}
      response = requests.get('https://api.basic.tech/your-endpoint', headers=headers)
  else:
      # Token is invalid, refresh it
      new_tokens = refresh_token(refresh_token)
      access_token = new_tokens['access_token']
      refresh_token = new_tokens['refresh_token']
      
      # Now use the new access token
      headers = {'Authorization': f'Bearer {access_token}'}
      response = requests.get('https://api.basic.tech/your-endpoint', headers=headers)
  ```

  ```javascript JavaScript theme={null}
  import jwtDecode from 'jwt-decode';

  async function refreshToken(refreshToken) {
      const response = await fetch('https://api.basic.tech/auth/token', {
          method: 'POST',
          headers: {
              'Content-Type': 'application/json'
          },
          body: JSON.stringify({ refresh_token: refreshToken })
      });
      return await response.json();
  }

  function isTokenValid(accessToken) {
      try {
          const decoded = jwtDecode(accessToken);
          // Check if token is expired
          return decoded.exp * 1000 > Date.now();
      } catch (error) {
          return false;
      }
  }

  // Example usage
  if (isTokenValid(accessToken)) {
      // Token is valid, proceed with API calls
      const response = await fetch('https://api.basic.tech/your-endpoint', {
          headers: {
              'Authorization': `Bearer ${accessToken}`
          }
      });
  } else {
      // Token is invalid, refresh it
      const newTokens = await refreshToken(refreshToken);
      accessToken = newTokens.access_token;
      refreshToken = newTokens.refresh_token;
      
      // Now use the new access token
      const response = await fetch('https://api.basic.tech/your-endpoint', {
          headers: {
              'Authorization': `Bearer ${accessToken}`
          }
      });
  }
  ```

  ```php PHP theme={null}
  <?php
  use Firebase\JWT\JWT;

  function refreshToken($refreshToken) {
      $ch = curl_init('https://api.basic.tech/auth/token');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json'
      ]);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
          'refresh_token' => $refreshToken
      ]));
      
      $response = curl_exec($ch);
      curl_close($ch);
      
      return json_decode($response, true);
  }

  function isTokenValid($accessToken) {
      try {
          $decoded = JWT::decode($accessToken, null, false);
          return $decoded->exp > time();
      } catch (Exception $e) {
          return false;
      }
  }

  // Example usage
  if (isTokenValid($accessToken)) {
      // Token is valid, proceed with API calls
      $ch = curl_init('https://api.basic.tech/your-endpoint');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Authorization: Bearer ' . $accessToken
      ]);
      $response = curl_exec($ch);
      curl_close($ch);
  } else {
      // Token is invalid, refresh it
      $newTokens = refreshToken($refreshToken);
      $accessToken = $newTokens['access_token'];
      $refreshToken = $newTokens['refresh_token'];
      
      // Now use the new access token
      $ch = curl_init('https://api.basic.tech/your-endpoint');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Authorization: Bearer ' . $accessToken
      ]);
      $response = curl_exec($ch);
      curl_close($ch);
  }
  ?>
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "time"
      "net/http"
      "io/ioutil"
      "encoding/json"
      "github.com/golang-jwt/jwt/v5"
  )

  type TokenResponse struct {
      AccessToken  string `json:"access_token"`
      RefreshToken string `json:"refresh_token"`
  }

  func refreshToken(refreshToken string) (*TokenResponse, error) {
      payload := map[string]string{
          "refresh_token": refreshToken,
      }
      jsonData, _ := json.Marshal(payload)

      req, _ := http.NewRequest("POST", "https://api.basic.tech/auth/token", bytes.NewBuffer(jsonData))
      req.Header.Set("Content-Type", "application/json")

      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
          return nil, err
      }
      defer resp.Body.Close()

      var tokenResp TokenResponse
      err = json.NewDecoder(resp.Body).Decode(&tokenResp)
      return &tokenResp, err
  }

  func isTokenValid(accessToken string) bool {
      token, _, err := jwt.NewParser().ParseUnverified(accessToken, jwt.MapClaims{})
      if err != nil {
          return false
      }

      if claims, ok := token.Claims.(jwt.MapClaims); ok {
          exp := claims["exp"].(float64)
          return int64(exp) > time.Now().Unix()
      }
      return false
  }

  func main() {
      if isTokenValid(accessToken) {
          // Token is valid, proceed with API calls
          req, _ := http.NewRequest("GET", "https://api.basic.tech/your-endpoint", nil)
          req.Header.Add("Authorization", "Bearer "+accessToken)

          client := &http.Client{}
          resp, _ := client.Do(req)
          defer resp.Body.Close()
          body, _ := ioutil.ReadAll(resp.Body)
          fmt.Println(string(body))
      } else {
          // Token is invalid, refresh it
          newTokens, err := refreshToken(refreshToken)
          if err != nil {
              fmt.Println("Error refreshing token:", err)
              return
          }
          
          accessToken = newTokens.AccessToken
          refreshToken = newTokens.RefreshToken
          
          // Now use the new access token
          req, _ := http.NewRequest("GET", "https://api.basic.tech/your-endpoint", nil)
          req.Header.Add("Authorization", "Bearer "+accessToken)

          client := &http.Client{}
          resp, _ := client.Do(req)
          defer resp.Body.Close()
          body, _ := ioutil.ReadAll(resp.Body)
          fmt.Println(string(body))
      }
  }
  ```

  ```java Java theme={null}
  import io.jsonwebtoken.Claims;
  import io.jsonwebtoken.Jwts;
  import java.util.Date;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URI;
  import com.google.gson.Gson;

  class TokenResponse {
      String access_token;
      String refresh_token;
  }

  public class TokenValidator {
      private static final HttpClient client = HttpClient.newHttpClient();
      private static final Gson gson = new Gson();

      public static TokenResponse refreshToken(String refreshToken) throws Exception {
          String json = String.format("{\"refresh_token\":\"%s\"}", refreshToken);
          
          HttpRequest request = HttpRequest.newBuilder()
              .uri(URI.create("https://api.basic.tech/auth/token"))
              .header("Content-Type", "application/json")
              .POST(HttpRequest.BodyPublishers.ofString(json))
              .build();

          HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
          return gson.fromJson(response.body(), TokenResponse.class);
      }

      public static boolean isTokenValid(String accessToken) {
          try {
              Claims claims = Jwts.parserBuilder()
                  .build()
                  .parseClaimsJwt(accessToken)
                  .getBody();
              
              Date expiration = claims.getExpiration();
              return expiration.after(new Date());
          } catch (Exception e) {
              return false;
          }
      }

      public static void main(String[] args) {
          if (isTokenValid(accessToken)) {
              // Token is valid, proceed with API calls
              HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create("https://api.basic.tech/your-endpoint"))
                  .header("Authorization", "Bearer " + accessToken)
                  .build();

              try {
                  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                  System.out.println(response.body());
              } catch (Exception e) {
                  e.printStackTrace();
              }
          } else {
              // Token is invalid, refresh it
              try {
                  TokenResponse newTokens = refreshToken(refreshToken);
                  accessToken = newTokens.access_token;
                  refreshToken = newTokens.refresh_token;
                  
                  // Now use the new access token
                  HttpRequest request = HttpRequest.newBuilder()
                      .uri(URI.create("https://api.basic.tech/your-endpoint"))
                      .header("Authorization", "Bearer " + accessToken)
                      .build();

                  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                  System.out.println(response.body());
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
  }
  ```
</CodeGroup>
