Skip to main content
The authorization code grant lets an external application act on behalf of a user who has explicitly consented to access. The resulting token carries the user’s identity and permissions.

When to Use

Use the authorization code grant when:
  • You are building an external customer portal that needs to display or modify user-specific data.
  • A third-party application needs to act as a specific user (e.g. a mobile app or a partner platform).
  • You need to respect per-user permissions and data visibility rules in external contexts.
For automation or admin APIs that do not involve a specific user, use client credentials instead.

How It Works

1

User initiates authorization

The external application redirects the user to /oauth/authorize with the app’s client_id and a redirect_uri.
2

User logs in (if needed) and consents

Core’s login page handles authentication. After login, the user sees a consent screen listing the app requesting access. They can Authorize or Deny.
3

Authorization code is issued

After consent, the user is redirected back to the redirect_uri with a one-time code parameter.
4

Code is exchanged for a token

The external application exchanges the code for an access token. The token is scoped to the user.
5

Token is used for API requests

The token is attached to requests to /api/user/* routes. The authenticated user’s permissions apply.

Setting Up

1. Create an App Client

In Developer → Apps, create a new app client with Authorization code as the grant type. Add your application’s callback URL(s) as Redirect URIs.
Only redirect URIs you have registered are accepted. Unregistered URIs will be rejected by Passport.

2. Redirect the User to Authorize

Construct the authorization URL and redirect the user:
const params = new URLSearchParams({
  client_id: 'your-client-uuid',
  redirect_uri: 'https://myportal.com/oauth/callback',
  response_type: 'code',
  scope: '',
  state: crypto.randomUUID(), // CSRF protection — store and verify later
});

window.location.href = `https://yourapp.test/oauth/authorize?${params}`;
If the user is not logged in, they are redirected to the login page first, then returned to the authorization screen after authentication.

3. Handle the Callback

After the user consents, your application receives a code and state at the redirect_uri:
https://myportal.com/oauth/callback?code=abc123&state=xyz
Verify the state matches what you generated, then exchange the code for a token:
curl -X POST https://yourapp.test/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "your-client-uuid",
    "client_secret": "your-client-secret",
    "redirect_uri": "https://myportal.com/oauth/callback",
    "code": "abc123"
  }'
{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
  "refresh_token": "def502..."
}

4. Make Authenticated Requests

Use the token on /api/v1/* routes:
curl -X GET https://yourapp.test/api/v1/identity \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...'

Defining API Routes

User-authenticated routes are defined in routes/api.php under the /v1 prefix with the CoreApiAuthenticate middleware, which accepts both user access tokens and client credentials tokens:
routes/api.php
Route::middleware([CoreApiAuthenticate::class])->prefix('v1')->group(function () {
    Route::get('/resource', [Api\ResourceController::class, 'index']);
});
Inside controllers, auth()->user() returns the authenticated User model (when using a user token) or null (when using a client credentials token). Use Auth::guard('api')->client() to retrieve the app client when applicable. When a user visits /oauth/authorize, they see a consent screen that:
  • Displays the requesting app’s name.
  • Lists any requested scopes (if configured).
  • Provides Authorize and Deny buttons.
The consent screen uses the brand logo from config('brand.icon') and is styled to match your application.

Refreshing Tokens

Use the refresh_token grant to obtain a new access token without requiring user re-authorization:
cURL
curl -X POST https://yourapp.test/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "def502...",
    "client_id": "your-client-uuid",
    "client_secret": "your-client-secret",
    "scope": ""
  }'

Next Steps