Skip to content
Last updated

Authorization Code Flow

The Authorization Code Flow is the recommended OAuth2 flow for server-side applications where the client secret can be securely stored.

Flow Overview

┌──────────┐
│   User   │
└─────┬────┘
      │ 1. Initiate login
      ▼
┌──────────────┐
│  Your App    │
└──────┬───────┘
       │ 2. Redirect to authorization URL
       ▼
  ┌──────────┐
  │  Askara  │
  └────┬─────┘
       │ 3. Show login/consent page
       ▼
  ┌──────────┐
  │   User   │
  └────┬─────┘
       │ 4. Authorize application
       ▼
  ┌──────────┐
  │  Askara  │
  └────┬─────┘
       │ 5. Redirect with authorization code
       ▼
┌──────────────┐
│  Your App    │
└──────┬───────┘
       │ 6. Exchange code for token
       ▼
  ┌──────────┐
  │  Askara  │
  └────┬─────┘
       │ 7. Return access & refresh tokens
       ▼
┌──────────────┐
│  Your App    │
└──────┬───────┘
       │ 8. Authentication complete
       ▼
┌──────────┐
│   User   │
└──────────┘

Implementation

Step 1: Generate Authorization URL

Generate a random state parameter for CSRF protection and store it securely (session, cookie, or database).

Build the authorization URL:

https://app.askara.ai/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=profile%20organization&state=STATE

Parameters:

  • response_type: Must be code
  • client_id: Your application's client ID
  • redirect_uri: Your callback URL (must match registration)
  • scope: Space-separated list of permissions (profile organization)
  • state: Random string for CSRF protection (required)
  • code_challenge and code_challenge_method: PKCE parameters (S256). Required for public clients, that is clients without a client secret, and for any client configured to require PKCE. See PKCE.

Redirect the user to this URL. They will authenticate and authorize your application.

Step 2: Handle Authorization Callback

After authorization, Askara redirects to your redirect_uri with query parameters:

https://your-app.com/callback?code=AUTHORIZATION_CODE&state=STATE

Verify the state parameter matches your stored value to prevent CSRF attacks.

Step 3: Exchange Code for Access Token

Make a server-side POST request to exchange the authorization code for tokens. The body must be form-encoded, as defined by the OAuth2 specification (RFC 6749):

POST https://api.askara.ai/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

Send client_secret if your client is confidential. A public client has no secret: it sends the PKCE code_verifier instead (see PKCE).

Response:

{
  "token_type": "Bearer",
  "expires_in": 3600,
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "def502003f8a8c7..."
}

Important: Store both tokens securely in your database.

Step 4: Use Access Token

Include the access token in API requests:

GET https://api.askara.ai/me
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

Security Considerations

State Parameter

  • Generate a cryptographically secure random string (minimum 16 characters)
  • Store securely and validate on callback
  • Use once and discard after validation

PKCE

  • Generate a random code_verifier for each authorization request and keep it on your side
  • Send code_challenge (the base64url-encoded SHA-256 hash of the verifier) with code_challenge_method=S256 in the authorization URL
  • Send the original code_verifier when you exchange the code in Step 3
  • Required for public clients, optional for confidential clients unless Askara configured your client to require it

Client Secret

  • Never expose in client-side code
  • Store in environment variables or secure configuration
  • Use HTTPS for all token exchanges

Authorization Code

  • Single-use only
  • Short-lived (valid for 10 minutes)
  • Must be exchanged on server-side

Error Handling

Authorization Errors

Only a successful authorization redirects to your redirect_uri (with code and state). If the authorization request is invalid (for example invalid_request for missing or invalid parameters, or unauthorized_client for a client that is not allowed to use this flow), Askara shows the error to the user on its own authorization page and does not call your callback.

Do not rely on an error redirect: your application must also handle a user who denies or abandons the authorization without ever reaching your redirect_uri, for example with a timeout on the login attempt.

Token Exchange Errors

{
  "error": "invalid_grant",
  "error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
  "hint": "Authorization code has expired"
}

Rely on the error value only: error_description and hint are meant for debugging and their wording may change.

Common errors:

  • invalid_grant (HTTP 400): Code expired or already used
  • invalid_client (HTTP 401): Invalid client credentials
  • invalid_request (HTTP 400): Missing required parameters

Code Example

// Step 1: Generate authorization URL
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;

$authUrl = 'https://app.askara.ai/authorize?' . http_build_query([
    'response_type' => 'code',
    'client_id' => getenv('ASKARA_CLIENT_ID'),
    'redirect_uri' => 'https://your-app.com/callback',
    'scope' => 'profile organization',
    'state' => $state
]);

header('Location: ' . $authUrl);

// Step 2: Handle callback
if ($_GET['state'] !== $_SESSION['oauth_state']) {
    die('Invalid state parameter');
}

$code = $_GET['code'];

// Step 3: Exchange code for token
$response = $httpClient->post('https://api.askara.ai/oauth2/token', [
    'form_params' => [
        'grant_type' => 'authorization_code',
        'code' => $code,
        'redirect_uri' => 'https://your-app.com/callback',
        'client_id' => getenv('ASKARA_CLIENT_ID'),
        'client_secret' => getenv('ASKARA_CLIENT_SECRET')
    ]
]);

$tokens = json_decode($response->getBody(), true);
// Store $tokens['access_token'] and $tokens['refresh_token']

Next Steps