docs: adds laravel forge app connection docs
@@ -125,6 +125,7 @@
|
|||||||
"integrations/app-connections/hashicorp-vault",
|
"integrations/app-connections/hashicorp-vault",
|
||||||
"integrations/app-connections/heroku",
|
"integrations/app-connections/heroku",
|
||||||
"integrations/app-connections/humanitec",
|
"integrations/app-connections/humanitec",
|
||||||
|
"integrations/app-connections/laravel-forge",
|
||||||
"integrations/app-connections/ldap",
|
"integrations/app-connections/ldap",
|
||||||
"integrations/app-connections/mssql",
|
"integrations/app-connections/mssql",
|
||||||
"integrations/app-connections/mysql",
|
"integrations/app-connections/mysql",
|
||||||
|
|||||||
|
After Width: | Height: | Size: 176 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 333 KiB |
|
After Width: | Height: | Size: 504 KiB |
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 200 KiB |
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
title: "Laravel Forge Connection"
|
||||||
|
description: "Learn how to configure a Laravel Forge Connection for Infisical."
|
||||||
|
---
|
||||||
|
|
||||||
|
Infisical supports the use of [API Tokens](https://forge.laravel.com/docs/api#create-a-new-api-token) to connect with Laravel Forge.
|
||||||
|
|
||||||
|
## Create Laravel Forge API Token
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
<Step title="From your Laravel Forge dashboard, click on your user avatar and go to 'API'">
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Click 'Create Token'">
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Provide Token Information">
|
||||||
|
Provide a name for your token and select the following permissions:
|
||||||
|
- `user:view`
|
||||||
|
- `organization:view`
|
||||||
|
- `server:view`
|
||||||
|
- `site:manage-environment`
|
||||||
|
|
||||||
|
Then click 'Add token'.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</Step>
|
||||||
|
<Step title="Copy the token securely">
|
||||||
|
Make sure to copy the token now—you won’t be able to access it again.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
## Create a Laravel Forge Connection in Infisical
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="Infisical UI">
|
||||||
|
<Steps>
|
||||||
|
<Step title="Navigate to App Connections">
|
||||||
|
In your Infisical dashboard, navigate to the **App Connections** page in the desired project.
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Select Laravel Forge Connection">
|
||||||
|
Click **+ Add Connection** and choose **Laravel Forge** Connection from the list of integrations.
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Fill out the Laravel Forge Connection form">
|
||||||
|
Complete the form by providing:
|
||||||
|
- A descriptive name for the connection
|
||||||
|
- An optional description
|
||||||
|
- The API Token from the previous step
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Connection created">
|
||||||
|
After submitting the form, your **Laravel Forge Connection** will be successfully created and ready to use with your Infisical project.
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab title="API">
|
||||||
|
To create a Laravel Forge Connection via API, send a request to the [Create Laravel Forge Connection](/api-reference/endpoints/app-connections/laravel-forge/create) endpoint.
|
||||||
|
|
||||||
|
### Sample request
|
||||||
|
|
||||||
|
```bash Request
|
||||||
|
curl --request POST \
|
||||||
|
--url https://app.infisical.com/api/v1/app-connections/laravel-forge \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"name": "my-laravel-forge-connection",
|
||||||
|
"method": "api-token",
|
||||||
|
"projectId": "7ffbb072-2575-495a-b5b0-127f88caef78",
|
||||||
|
"credentials": {
|
||||||
|
"apiToken": "[API TOKEN]"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample response
|
||||||
|
|
||||||
|
```bash Response
|
||||||
|
{
|
||||||
|
"appConnection": {
|
||||||
|
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
|
||||||
|
"name": "my-laravel-forge-connection",
|
||||||
|
"description": null,
|
||||||
|
"projectId": "7ffbb072-2575-495a-b5b0-127f88caef78",
|
||||||
|
"version": 1,
|
||||||
|
"orgId": "abcdef12-3456-7890-abcd-ef1234567890",
|
||||||
|
"createdAt": "2025-10-13T10:15:00.000Z",
|
||||||
|
"updatedAt": "2025-10-13T10:15:00.000Z",
|
||||||
|
"isPlatformManagedCredentials": false,
|
||||||
|
"credentialsHash": "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
"app": "laravel-forge",
|
||||||
|
"method": "api-token",
|
||||||
|
"credentials": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
@@ -17,10 +17,10 @@ export const SecretSyncModalHeader = ({ destination, isConfigured }: Props) => {
|
|||||||
<img
|
<img
|
||||||
alt={`${destinationDetails.name} logo`}
|
alt={`${destinationDetails.name} logo`}
|
||||||
src={`/images/integrations/${destinationDetails.image}`}
|
src={`/images/integrations/${destinationDetails.image}`}
|
||||||
className="h-12 w-12 rounded-md bg-bunker-500 p-2"
|
className="bg-bunker-500 h-12 w-12 rounded-md p-2"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center text-mineshaft-300">
|
<div className="text-mineshaft-300 flex items-center">
|
||||||
{destinationDetails.name} Sync
|
{destinationDetails.name} Sync
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -28,8 +28,8 @@ export const SecretSyncModalHeader = ({ destination, isConfigured }: Props) => {
|
|||||||
className="mb-1 ml-1"
|
className="mb-1 ml-1"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<div className="inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
|
<div className="bg-yellow/20 text-yellow inline-block rounded-md px-1.5 text-sm opacity-80 hover:opacity-100">
|
||||||
<FontAwesomeIcon icon={faBookOpen} className="mr-1 mb-[0.03rem] text-[12px]" />
|
<FontAwesomeIcon icon={faBookOpen} className="mb-[0.03rem] mr-1 text-[12px]" />
|
||||||
<span>Docs</span>
|
<span>Docs</span>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faArrowUpRightFromSquare}
|
icon={faArrowUpRightFromSquare}
|
||||||
@@ -38,7 +38,7 @@ export const SecretSyncModalHeader = ({ destination, isConfigured }: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm leading-4 text-mineshaft-400">
|
<p className="text-mineshaft-400 text-sm leading-4">
|
||||||
{isConfigured
|
{isConfigured
|
||||||
? `Edit ${destinationDetails.name} Sync`
|
? `Edit ${destinationDetails.name} Sync`
|
||||||
: `Sync secrets to ${destinationDetails.name}`}
|
: `Sync secrets to ${destinationDetails.name}`}
|
||||||
|
|||||||
@@ -57,7 +57,14 @@ import { SupabaseConnectionMethod } from "@app/hooks/api/appConnections/types/su
|
|||||||
|
|
||||||
export const APP_CONNECTION_MAP: Record<
|
export const APP_CONNECTION_MAP: Record<
|
||||||
AppConnection,
|
AppConnection,
|
||||||
{ name: string; image: string; size?: number; icon?: IconDefinition; enterprise?: boolean }
|
{
|
||||||
|
name: string;
|
||||||
|
image: string;
|
||||||
|
size?: number;
|
||||||
|
icon?: IconDefinition;
|
||||||
|
enterprise?: boolean;
|
||||||
|
imageClassName?: string;
|
||||||
|
}
|
||||||
> = {
|
> = {
|
||||||
[AppConnection.AWS]: { name: "AWS", image: "Amazon Web Services.png" },
|
[AppConnection.AWS]: { name: "AWS", image: "Amazon Web Services.png" },
|
||||||
[AppConnection.GitHub]: { name: "GitHub", image: "GitHub.png" },
|
[AppConnection.GitHub]: { name: "GitHub", image: "GitHub.png" },
|
||||||
@@ -117,7 +124,11 @@ export const APP_CONNECTION_MAP: Record<
|
|||||||
},
|
},
|
||||||
[AppConnection.Okta]: { name: "Okta", image: "Okta.png" },
|
[AppConnection.Okta]: { name: "Okta", image: "Okta.png" },
|
||||||
[AppConnection.Redis]: { name: "Redis", image: "Redis.png" },
|
[AppConnection.Redis]: { name: "Redis", image: "Redis.png" },
|
||||||
[AppConnection.LaravelForge]: { name: "Laravel Forge", image: "Laravel Forge.png" }
|
[AppConnection.LaravelForge]: {
|
||||||
|
name: "Laravel Forge",
|
||||||
|
image: "Laravel Forge.png",
|
||||||
|
imageClassName: "object-contain"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) => {
|
export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) => {
|
||||||
|
|||||||
@@ -14,22 +14,22 @@ export const AppConnectionHeader = ({ app, isConnected, onBack }: Props) => {
|
|||||||
const appDetails = APP_CONNECTION_MAP[app];
|
const appDetails = APP_CONNECTION_MAP[app];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 flex w-full items-start gap-2 border-b border-mineshaft-500 pb-4">
|
<div className="border-mineshaft-500 mb-4 flex w-full items-start gap-2 border-b pb-4">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
alt={`${appDetails.name} logo`}
|
alt={`${appDetails.name} logo`}
|
||||||
src={`/images/integrations/${appDetails.image}`}
|
src={`/images/integrations/${appDetails.image}`}
|
||||||
className="h-12 w-12 rounded-md bg-bunker-500 p-2"
|
className={`bg-bunker-500 h-12 w-12 rounded-md p-2 ${appDetails.imageClassName}`}
|
||||||
/>
|
/>
|
||||||
{appDetails.icon && (
|
{appDetails.icon && (
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={appDetails.icon}
|
icon={appDetails.icon}
|
||||||
className="absolute right-1 bottom-1 text-primary-700"
|
className="text-primary-700 absolute bottom-1 right-1"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center text-mineshaft-300">
|
<div className="text-mineshaft-300 flex items-center">
|
||||||
{appDetails.name}
|
{appDetails.name}
|
||||||
<a
|
<a
|
||||||
href={`https://infisical.com/docs/integrations/app-connections/${app}`}
|
href={`https://infisical.com/docs/integrations/app-connections/${app}`}
|
||||||
@@ -37,8 +37,8 @@ export const AppConnectionHeader = ({ app, isConnected, onBack }: Props) => {
|
|||||||
className="mb-1 ml-1"
|
className="mb-1 ml-1"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<div className="inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
|
<div className="bg-yellow/20 text-yellow inline-block rounded-md px-1.5 text-sm opacity-80 hover:opacity-100">
|
||||||
<FontAwesomeIcon icon={faBookOpen} className="mr-1 mb-[0.03rem] text-[12px]" />
|
<FontAwesomeIcon icon={faBookOpen} className="mb-[0.03rem] mr-1 text-[12px]" />
|
||||||
<span>Docs</span>
|
<span>Docs</span>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faArrowUpRightFromSquare}
|
icon={faArrowUpRightFromSquare}
|
||||||
@@ -47,14 +47,14 @@ export const AppConnectionHeader = ({ app, isConnected, onBack }: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm leading-4 text-mineshaft-400">
|
<p className="text-mineshaft-400 text-sm leading-4">
|
||||||
{isConnected ? `${appDetails.name} Connection` : `Connect to ${appDetails.name}`}
|
{isConnected ? `${appDetails.name} Connection` : `Connect to ${appDetails.name}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{onBack && (
|
{onBack && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="mt-1 ml-auto text-xs text-mineshaft-400 underline underline-offset-2 hover:text-mineshaft-300"
|
className="text-mineshaft-400 hover:text-mineshaft-300 ml-auto mt-1 text-xs underline underline-offset-2"
|
||||||
onClick={onBack}
|
onClick={onBack}
|
||||||
>
|
>
|
||||||
Select another App
|
Select another App
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col items-center justify-center py-2.5">
|
<div className="flex h-full flex-col items-center justify-center py-2.5">
|
||||||
<Spinner size="lg" className="text-mineshaft-500" />
|
<Spinner size="lg" className="text-mineshaft-500" />
|
||||||
<p className="mt-4 text-sm text-mineshaft-400">Loading options...</p>
|
<p className="text-mineshaft-400 mt-4 text-sm">Loading options...</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
placeholder="Search options..."
|
placeholder="Search options..."
|
||||||
className="bg-mineshaft-800 placeholder:text-mineshaft-400"
|
className="bg-mineshaft-800 placeholder:text-mineshaft-400"
|
||||||
/>
|
/>
|
||||||
<div className="grid h-118 grid-cols-4 content-start gap-2">
|
<div className="h-118 grid grid-cols-4 content-start gap-2">
|
||||||
{filteredOptions.slice(offset, perPage * page)?.map((option) => {
|
{filteredOptions.slice(offset, perPage * page)?.map((option) => {
|
||||||
const {
|
const {
|
||||||
image,
|
image,
|
||||||
@@ -78,9 +78,9 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
? handlePopUpOpen("upgradePlan")
|
? handlePopUpOpen("upgradePlan")
|
||||||
: onSelect(option.app)
|
: onSelect(option.app)
|
||||||
}
|
}
|
||||||
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
|
className="border-mineshaft-600 bg-mineshaft-700 hover:bg-mineshaft-600 group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border p-4 duration-200"
|
||||||
>
|
>
|
||||||
<div className="relative">
|
{image && (
|
||||||
<img
|
<img
|
||||||
src={`/images/integrations/${image}`}
|
src={`/images/integrations/${image}`}
|
||||||
style={{
|
style={{
|
||||||
@@ -89,14 +89,16 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
className="mt-auto"
|
className="mt-auto"
|
||||||
alt={`${name} logo`}
|
alt={`${name} logo`}
|
||||||
/>
|
/>
|
||||||
{icon && (
|
)}
|
||||||
|
{icon && (
|
||||||
|
<div className="relative">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
className="absolute -right-1.5 -bottom-1.5 text-primary-700"
|
className="text-primary-700 absolute -bottom-1.5 -right-1.5"
|
||||||
size="xl"
|
size="xl"
|
||||||
icon={icon}
|
icon={icon}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
<div className="mt-auto max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
<div className="mt-auto max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
@@ -125,7 +127,7 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
service you're looking for,`}{" "}
|
service you're looking for,`}{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="underline hover:text-mineshaft-300"
|
className="hover:text-mineshaft-300 underline"
|
||||||
href="https://infisical.com/slack"
|
href="https://infisical.com/slack"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
@@ -134,7 +136,7 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
or{" "}
|
or{" "}
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="underline hover:text-mineshaft-300"
|
className="hover:text-mineshaft-300 underline"
|
||||||
href="https://github.com/Infisical/infisical/discussions"
|
href="https://github.com/Infisical/infisical/discussions"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
@@ -145,7 +147,7 @@ export const AppConnectionsSelect = ({ onSelect, projectType }: Props) => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="-ml-3 flex items-center gap-1.5 text-mineshaft-400">
|
<div className="text-mineshaft-400 -ml-3 flex items-center gap-1.5">
|
||||||
<span className="text-xs">
|
<span className="text-xs">
|
||||||
Don't see the third-party service you're looking for?
|
Don't see the third-party service you're looking for?
|
||||||
</span>
|
</span>
|
||||||
|
|||||||