Compare commits

...

15 Commits

Author SHA1 Message Date
e88b0ad3c4 Update python.mdx 2024-01-11 01:25:10 +04:00
74644fd8bb Added cryptography docs and fixed formatting 2024-01-11 01:12:38 +04:00
2069ac1554 Added CSharp and removed unfinished SDK's 2024-01-11 01:12:26 +04:00
5a2516e0a7 Removed unsupported languages to remove clutter 2024-01-11 01:12:17 +04:00
b52bc3bed7 Added CSharp docs 2024-01-11 01:12:05 +04:00
b815e3eb56 Merge pull request #1291 from Infisical/daniel/fix-sdk-contribution-image
(Fix): Image in SDK contribution guide not loading
2024-01-08 14:56:27 -05:00
31231cfcca Update developing.mdx 2024-01-08 23:30:10 +04:00
ee772e4a77 allow reading universal auth creds from env in agent 2024-01-07 17:00:42 -05:00
7bc29c5981 Merge pull request #1285 from Infisical/query-by-secret-version
Add version query param to GET secret raw and regular endpoints
2024-01-07 16:07:49 -05:00
e9a89930da Merge pull request #1284 from Infisical/multi-integration-auth
Enable new integration auth credential for each new integration
2024-01-07 14:49:04 -05:00
b85499859c Merge pull request #1286 from Infisical/identities-ipv6
Add IPv6 consideration to default universal auth IP allowlist
2024-01-07 16:37:06 +01:00
7f17194c0f Add IPv6 consideration to default identities IP allowlist 2024-01-07 16:32:25 +01:00
1e1ad450d2 Add version query param to GET secret endpoint 2024-01-07 14:25:33 +01:00
45d96be1ff added base64 support for config and templates 2024-01-06 23:43:04 -05:00
12840bfdbd add exit after auth setting 2024-01-06 17:17:21 -05:00
19 changed files with 854 additions and 134 deletions

View File

@ -550,7 +550,7 @@ export const attachIdentityUniversalAuth = async (req: Request, res: Response) =
// validate trusted ips // validate trusted ips
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => { const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({ if (!plan.ipAllowlisting && (clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && clientSecretTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
}); });
@ -564,7 +564,7 @@ export const attachIdentityUniversalAuth = async (req: Request, res: Response) =
}); });
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => { const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
if (!plan.ipAllowlisting && accessTokenTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({ if (!plan.ipAllowlisting && (accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" && accessTokenTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
}); });
@ -750,7 +750,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
let reformattedClientSecretTrustedIps; let reformattedClientSecretTrustedIps;
if (clientSecretTrustedIps) { if (clientSecretTrustedIps) {
reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => { reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({ if (!plan.ipAllowlisting && (clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" && clientSecretTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
}); });
@ -767,7 +767,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
let reformattedAccessTokenTrustedIps; let reformattedAccessTokenTrustedIps;
if (accessTokenTrustedIps) { if (accessTokenTrustedIps) {
reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => { reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
if (!plan.ipAllowlisting && accessTokenTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({ if (!plan.ipAllowlisting && (accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" && accessTokenTrustedIp.ipAddress !== "::/0")) return res.status(400).send({
message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range." message: "Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
}); });

View File

@ -348,7 +348,7 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
} }
*/ */
const { const {
query: { secretPath, environment, workspaceId, type, include_imports }, query: { secretPath, environment, workspaceId, type, include_imports, version },
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req); } = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
@ -371,7 +371,8 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
type, type,
secretPath, secretPath,
authData: req.authData, authData: req.authData,
include_imports include_imports,
version
}); });
const key = await BotService.getWorkspaceKeyWithBot({ const key = await BotService.getWorkspaceKeyWithBot({
@ -865,7 +866,7 @@ export const getSecrets = async (req: Request, res: Response) => {
*/ */
export const getSecretByName = async (req: Request, res: Response) => { export const getSecretByName = async (req: Request, res: Response) => {
const { const {
query: { secretPath, environment, workspaceId, type, include_imports }, query: { secretPath, environment, workspaceId, type, include_imports, version },
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameV3, req); } = await validateRequest(reqValidator.GetSecretByNameV3, req);
@ -888,7 +889,8 @@ export const getSecretByName = async (req: Request, res: Response) => {
type, type,
secretPath, secretPath,
authData: req.authData, authData: req.authData,
include_imports include_imports,
version
}); });
return res.status(200).send({ return res.status(200).send({

View File

@ -611,42 +611,81 @@ export const getSecretHelper = async ({
type, type,
authData, authData,
secretPath = "/", secretPath = "/",
include_imports = true include_imports = true,
version
}: GetSecretParams) => { }: GetSecretParams) => {
const secretBlindIndex = await generateSecretBlindIndexHelper({ const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName, secretName,
workspaceId: new Types.ObjectId(workspaceId) workspaceId: new Types.ObjectId(workspaceId)
}); });
let secret: ISecret | null | undefined = null; let secret: ISecret | null | undefined = null;
// if using service token filter towards the folderId by secretpath // if using service token filter towards the folderId by secretpath
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
// try getting personal secret first (if exists) // try getting personal secret first (if exists)
secret = await Secret.findOne({ if (version === undefined) {
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
folder: folderId,
type: type ?? SECRET_PERSONAL,
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
}).lean();
if (!secret) {
// case: failed to find personal secret matching criteria
// -> find shared secret matching criteria
secret = await Secret.findOne({ secret = await Secret.findOne({
secretBlindIndex, secretBlindIndex,
workspace: new Types.ObjectId(workspaceId), workspace: new Types.ObjectId(workspaceId),
environment, environment,
folder: folderId, folder: folderId,
type: SECRET_SHARED type: type ?? SECRET_PERSONAL,
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
}).lean(); }).lean();
} else {
const secretVersion = await SecretVersion.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
folder: folderId,
type: type ?? SECRET_PERSONAL,
version
}).lean();
if (secretVersion) {
secret = await new Secret({
...secretVersion,
_id: secretVersion?.secret
});
}
} }
if (!secret) {
// case: failed to find personal secret matching criteria
// -> find shared secret matching criteria
if (version === undefined) {
secret = await Secret.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
folder: folderId,
type: SECRET_SHARED
}).lean();
} else {
const secretVersion = await SecretVersion.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
folder: folderId,
type: SECRET_SHARED,
version
}).lean();
if (secretVersion) {
secret = await new Secret({
...secretVersion,
_id: secretVersion?.secret
});
}
}
}
if (!secret && include_imports) { if (!secret && include_imports) {
// if still no secret found search in imported secret and retreive // if still no secret found search in imported secret and retreive
secret = await getAnImportedSecret(secretName, workspaceId.toString(), environment, folderId); secret = await getAnImportedSecret(secretName, workspaceId.toString(), environment, folderId, version);
} }
if (!secret) throw SecretNotFoundError(); if (!secret) throw SecretNotFoundError();

View File

@ -38,6 +38,7 @@ export interface GetSecretParams {
type?: "shared" | "personal"; type?: "shared" | "personal";
authData: AuthData; authData: AuthData;
include_imports?: boolean; include_imports?: boolean;
version?: number;
} }
export interface UpdateSecretParams { export interface UpdateSecretParams {

View File

@ -1,5 +1,6 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { generateSecretBlindIndexHelper } from "../helpers"; import { generateSecretBlindIndexHelper } from "../helpers";
import { SecretVersion } from "../ee/models";
import { Folder, ISecret, Secret, SecretImport } from "../models"; import { Folder, ISecret, Secret, SecretImport } from "../models";
import { getFolderByPath } from "./FolderService"; import { getFolderByPath } from "./FolderService";
@ -9,7 +10,8 @@ export const getAnImportedSecret = async (
secretName: string, secretName: string,
workspaceId: string, workspaceId: string,
environment: string, environment: string,
folderId = "root" folderId = "root",
version?: number
) => { ) => {
const secretBlindIndex = await generateSecretBlindIndexHelper({ const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName, secretName,
@ -48,10 +50,26 @@ export const getAnImportedSecret = async (
}); });
if (importedSecByFid.length === 0) return; if (importedSecByFid.length === 0) return;
const secret = await Secret.findOne({ let secret;
workspace: workspaceId, if (version === undefined) {
secretBlindIndex secret = await Secret.findOne({
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean() workspace: workspaceId,
secretBlindIndex
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean()
} else {
const secretVersion = await SecretVersion.findOne({
workspace: workspaceId,
secretBlindIndex,
version
}).or(importedSecByFid.map(({ environment, folderId }) => ({ environment, folder: folderId }))).lean();
if (secretVersion) {
secret = await new Secret({
...secretVersion,
_id: secretVersion.secret,
});
}
}
return secret; return secret;
}; };

View File

@ -108,14 +108,14 @@ export const AddUniversalAuthToIdentityV1 = z.object({
}) })
.array() .array()
.min(1) .min(1)
.default([{ ipAddress: "0.0.0.0/0" }]), .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
accessTokenTrustedIps: z accessTokenTrustedIps: z
.object({ .object({
ipAddress: z.string().trim(), ipAddress: z.string().trim(),
}) })
.array() .array()
.min(1) .min(1)
.default([{ ipAddress: "0.0.0.0/0" }]), .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
accessTokenTTL: z.number().int().min(1).refine(value => value !== 0, { accessTokenTTL: z.number().int().min(1).refine(value => value !== 0, {
message: "accessTokenTTL must have a non zero number", message: "accessTokenTTL must have a non zero number",
}).default(2592000), }).default(2592000),

View File

@ -246,7 +246,15 @@ export const GetSecretByNameRawV3 = z.object({
include_imports: z include_imports: z
.enum(["true", "false"]) .enum(["true", "false"])
.default("true") .default("true")
.transform((value) => value === "true") .transform((value) => value === "true"),
version: z
.string()
.trim()
.optional()
.transform((value) => value === undefined ? undefined : parseInt(value, 10))
.refine((value) => value === undefined || !isNaN(value), {
message: "Version must be a number",
})
}) })
}); });
@ -318,7 +326,15 @@ export const GetSecretByNameV3 = z.object({
include_imports: z include_imports: z
.enum(["true", "false"]) .enum(["true", "false"])
.default("true") .default("true")
.transform((value) => value === "true") .transform((value) => value === "true"),
version: z
.string()
.trim()
.optional()
.transform((value) => value === undefined ? undefined : parseInt(value, 10))
.refine((value) => value === undefined || !isNaN(value), {
message: "Version must be a number",
})
}), }),
params: z.object({ params: z.object({
secretName: z.string().trim() secretName: z.string().trim()

View File

@ -5,6 +5,7 @@ package cmd
import ( import (
"bytes" "bytes"
"encoding/base64"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -37,7 +38,8 @@ type Config struct {
} }
type InfisicalConfig struct { type InfisicalConfig struct {
Address string `yaml:"address"` Address string `yaml:"address"`
ExitAfterAuth bool `yaml:"exit-after-auth"`
} }
type AuthConfig struct { type AuthConfig struct {
@ -66,8 +68,9 @@ type SinkDetails struct {
} }
type Template struct { type Template struct {
SourcePath string `yaml:"source-path"` SourcePath string `yaml:"source-path"`
DestinationPath string `yaml:"destination-path"` Base64TemplateContent string `yaml:"base64-template-content"`
DestinationPath string `yaml:"destination-path"`
} }
func ReadFile(filePath string) ([]byte, error) { func ReadFile(filePath string) ([]byte, error) {
@ -107,12 +110,7 @@ func appendAPIEndpoint(address string) string {
return address + "/api" return address + "/api"
} }
func ParseAgentConfig(filePath string) (*Config, error) { func ParseAgentConfig(configFile []byte) (*Config, error) {
data, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, err
}
var rawConfig struct { var rawConfig struct {
Infisical InfisicalConfig `yaml:"infisical"` Infisical InfisicalConfig `yaml:"infisical"`
Auth struct { Auth struct {
@ -123,7 +121,7 @@ func ParseAgentConfig(filePath string) (*Config, error) {
Templates []Template `yaml:"templates"` Templates []Template `yaml:"templates"`
} }
if err := yaml.Unmarshal(data, &rawConfig); err != nil { if err := yaml.Unmarshal(configFile, &rawConfig); err != nil {
return nil, err return nil, err
} }
@ -205,6 +203,35 @@ func ProcessTemplate(templatePath string, data interface{}, accessToken string)
return &buf, nil return &buf, nil
} }
func ProcessBase64Template(encodedTemplate string, data interface{}, accessToken string) (*bytes.Buffer, error) {
// custom template function to fetch secrets from Infisical
decoded, err := base64.StdEncoding.DecodeString(encodedTemplate)
if err != nil {
return nil, err
}
templateString := string(decoded)
secretFunction := secretTemplateFunction(accessToken)
funcs := template.FuncMap{
"secret": secretFunction,
}
templateName := "base64Template"
tmpl, err := template.New(templateName).Funcs(funcs).Parse(templateString)
if err != nil {
return nil, err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return nil, err
}
return &buf, nil
}
type TokenManager struct { type TokenManager struct {
accessToken string accessToken string
accessTokenTTL time.Duration accessTokenTTL time.Duration
@ -219,10 +246,11 @@ type TokenManager struct {
newAccessTokenNotificationChan chan bool newAccessTokenNotificationChan chan bool
removeClientSecretOnRead bool removeClientSecretOnRead bool
cachedClientSecret string cachedClientSecret string
exitAfterAuth bool
} }
func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool) *TokenManager { func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool, exitAfterAuth bool) *TokenManager {
return &TokenManager{filePaths: fileDeposits, templates: templates, clientIdPath: clientIdPath, clientSecretPath: clientSecretPath, newAccessTokenNotificationChan: newAccessTokenNotificationChan, removeClientSecretOnRead: removeClientSecretOnRead} return &TokenManager{filePaths: fileDeposits, templates: templates, clientIdPath: clientIdPath, clientSecretPath: clientSecretPath, newAccessTokenNotificationChan: newAccessTokenNotificationChan, removeClientSecretOnRead: removeClientSecretOnRead, exitAfterAuth: exitAfterAuth}
} }
func (tm *TokenManager) SetToken(token string, accessTokenTTL time.Duration, accessTokenMaxTTL time.Duration) { func (tm *TokenManager) SetToken(token string, accessTokenTTL time.Duration, accessTokenMaxTTL time.Duration) {
@ -245,18 +273,26 @@ func (tm *TokenManager) GetToken() string {
// Fetches a new access token using client credentials // Fetches a new access token using client credentials
func (tm *TokenManager) FetchNewAccessToken() error { func (tm *TokenManager) FetchNewAccessToken() error {
clientIDAsByte, err := ReadFile(tm.clientIdPath) clientID := os.Getenv("INFISICAL_UNIVERSAL_AUTH_CLIENT_ID")
if err != nil { if clientID == "" {
return fmt.Errorf("unable to read client id from file path '%s' due to error: %v", tm.clientIdPath, err) clientIDAsByte, err := ReadFile(tm.clientIdPath)
if err != nil {
return fmt.Errorf("unable to read client id from file path '%s' due to error: %v", tm.clientIdPath, err)
}
clientID = string(clientIDAsByte)
} }
clientSecretAsByte, err := ReadFile(tm.clientSecretPath) clientSecret := os.Getenv("INFISICAL_UNIVERSAL_CLIENT_SECRET")
if err != nil { if clientSecret == "" {
if len(tm.cachedClientSecret) == 0 { clientSecretAsByte, err := ReadFile(tm.clientSecretPath)
return fmt.Errorf("unable to read client secret from file and no cached client secret found: %v", err) if err != nil {
} else { if len(tm.cachedClientSecret) == 0 {
clientSecretAsByte = []byte(tm.cachedClientSecret) return fmt.Errorf("unable to read client secret from file and no cached client secret found: %v", err)
} else {
clientSecretAsByte = []byte(tm.cachedClientSecret)
}
} }
clientSecret = string(clientSecretAsByte)
} }
// remove client secret after first read // remove client secret after first read
@ -264,13 +300,10 @@ func (tm *TokenManager) FetchNewAccessToken() error {
os.Remove(tm.clientSecretPath) os.Remove(tm.clientSecretPath)
} }
clientId := string(clientIDAsByte)
clientSecret := string(clientSecretAsByte)
// save as cache in memory // save as cache in memory
tm.cachedClientSecret = clientSecret tm.cachedClientSecret = clientSecret
err, loginResponse := universalAuthLogin(clientId, clientSecret) err, loginResponse := universalAuthLogin(clientID, clientSecret)
if err != nil { if err != nil {
return err return err
} }
@ -354,6 +387,11 @@ func (tm *TokenManager) ManageTokenLifecycle() {
} }
} }
if tm.exitAfterAuth {
time.Sleep(25 * time.Second)
os.Exit(0)
}
if accessTokenRefreshedTime.IsZero() { if accessTokenRefreshedTime.IsZero() {
accessTokenRefreshedTime = tm.accessTokenFetchedTime accessTokenRefreshedTime = tm.accessTokenFetchedTime
} else { } else {
@ -396,7 +434,14 @@ func (tm *TokenManager) FetchSecrets() {
token := tm.GetToken() token := tm.GetToken()
if token != "" { if token != "" {
for _, secretTemplate := range tm.templates { for _, secretTemplate := range tm.templates {
processedTemplate, err := ProcessTemplate(secretTemplate.SourcePath, nil, token) var processedTemplate *bytes.Buffer
var err error
if secretTemplate.SourcePath != "" {
processedTemplate, err = ProcessTemplate(secretTemplate.SourcePath, nil, token)
} else {
processedTemplate, err = ProcessBase64Template(secretTemplate.Base64TemplateContent, nil, token)
}
if err != nil { if err != nil {
log.Error().Msgf("template engine: unable to render secrets because %s. Will try again on next cycle", err) log.Error().Msgf("template engine: unable to render secrets because %s. Will try again on next cycle", err)
@ -449,12 +494,38 @@ var agentCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag config") util.HandleError(err, "Unable to parse flag config")
} }
if !FileExists(configPath) { var agentConfigInBytes []byte
log.Error().Msgf("Unable to locate %s. The provided agent config file path is either missing or incorrect", configPath)
agentConfigInBase64 := os.Getenv("INFISICAL_AGENT_CONFIG_BASE64")
if configPath != "" {
data, err := ioutil.ReadFile(configPath)
if err != nil {
if !FileExists(configPath) {
log.Error().Msgf("Unable to locate %s. The provided agent config file path is either missing or incorrect", configPath)
return
}
}
agentConfigInBytes = data
}
if agentConfigInBase64 != "" {
decodedAgentConfig, err := base64.StdEncoding.DecodeString(agentConfigInBase64)
if err != nil {
log.Error().Msgf("Unable to decode base64 config file because %v", err)
return
}
agentConfigInBytes = decodedAgentConfig
}
if !FileExists(configPath) && agentConfigInBase64 == "" {
log.Error().Msgf("No agent config file provided. Please provide a agent config file", configPath)
return return
} }
agentConfig, err := ParseAgentConfig(configPath) agentConfig, err := ParseAgentConfig(agentConfigInBytes)
if err != nil { if err != nil {
log.Error().Msgf("Unable to prase %s because %v. Please ensure that is follows the Infisical Agent config structure", configPath, err) log.Error().Msgf("Unable to prase %s because %v. Please ensure that is follows the Infisical Agent config structure", configPath, err)
return return
@ -471,7 +542,7 @@ var agentCmd = &cobra.Command{
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
filePaths := agentConfig.Sinks filePaths := agentConfig.Sinks
tm := NewTokenManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead) tm := NewTokenManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead, agentConfig.Infisical.ExitAfterAuth)
go tm.ManageTokenLifecycle() go tm.ManageTokenLifecycle()
go tm.FetchSecrets() go tm.FetchSecrets()

View File

@ -76,7 +76,7 @@ If the command handler fails to validate the input, an error will be returned to
<Frame caption="Execution flow diagram for the SDK from the target language to the base SDK. The execution flow is the same for all target languages."> <Frame caption="Execution flow diagram for the SDK from the target language to the base SDK. The execution flow is the same for all target languages.">
<img height="640" width="520" src="images/sdk-flow.png" /> <img height="640" width="520" src="/images/sdk-flow.png" />
</Frame> </Frame>

View File

@ -0,0 +1,391 @@
---
title: "C#"
icon: "C#"
---
If you're working with C#, the official [Infisical C# SDK](https://github.com/Infisical/sdk/tree/main/languages/csharp) package is the easiest way to fetch and work with secrets for your application.
## Basic Usage
```cs
using Infisical.Sdk;
namespace Example
{
class Program
{
static void Main(string[] args)
{
var settings = new ClientSettings
{
ClientId = "CLIENT_ID",
ClientSecret = "CLIENT_SECRET",
// SiteUrl = "http://localhost:8080", <-- This line can be omitted if you're using Infisical Cloud.
};
var infisical = new InfisicalClient(settings);
var options = new GetSecretOptions
{
SecretName = "TEST",
ProjectId = "PROJECT_ID",
Environment = "dev",
};
var secret = infisical.GetSecret(options);
Console.WriteLine($"The value of secret '{secret.SecretKey}', is: {secret.SecretValue}");
}
}
}
```
This example demonstrates how to use the Infisical C# SDK in a C# application. The application retrieves a secret named `TEST` from the `dev` environment of the `PROJECT_ID` project.
<Warning>
We do not recommend hardcoding your [Machine Identity Tokens](/platform/identities/overview). Setting it as an environment variable would be best.
</Warning>
# Installation
Run `npm` to add `@infisical/sdk` to your project.
```console
$ dotnet add package Infisical.Sdk
```
# Configuration
Import the SDK and create a client instance with your [Machine Identity](/platform/identities/universal-auth).
```cs
using Infisical.Sdk;
namespace Example
{
class Program
{
static void Main(string[] args)
{
var settings = new ClientSettings
{
ClientId = "CLIENT_ID",
ClientSecret = "CLIENT_SECRET",
};
var infisical = new InfisicalClient(settings); // <-- Your SDK instance!
}
}
}
```
### ClientSettings methods
<ParamField query="options" type="object">
<Expandable title="properties">
<ParamField query="ClientId" type="string" optional>
Your machine identity client ID.
</ParamField>
<ParamField query="ClientSecret" type="string" optional>
Your machine identity client secret.
</ParamField>
<ParamField query="AccessToken" type="string" optional>
An access token obtained from the machine identity login endpoint.
</ParamField>
<ParamField query="CacheTtl" type="number" default="300" optional>
Time-to-live (in seconds) for refreshing cached secrets.
If manually set to 0, caching will be disabled, this is not recommended.
</ParamField>
<ParamField query="SiteUrl()" type="string" default="https://app.infisical.com" optional>
Your self-hosted absolute site URL including the protocol (e.g. `https://app.infisical.com`)
</ParamField>
</Expandable>
</ParamField>
### Caching
To reduce the number of API requests, the SDK temporarily stores secrets it retrieves. By default, a secret remains cached for 5 minutes after it's first fetched. Each time it's fetched again, this 5-minute timer resets. You can adjust this caching duration by setting the "cacheTTL" option when creating the client.
## Working with Secrets
### client.ListSecrets(options)
```cs
var options = new ListSecretsOptions
{
ProjectId = "PROJECT_ID",
Environment = "dev",
Path = "/foo/bar",
AttachToProcessEnv = false,
};
var secrets = infisical.ListSecrets(options);
```
Retrieve all secrets within the Infisical project and environment that client is connected to
#### Parameters
<ParamField query="Parameters" type="object">
<Expandable title="properties">
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="ProjectId" type="string">
The project ID where the secret lives in.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where secrets should be fetched from.
</ParamField>
<ParamField query="AttachToProcessEnv" type="boolean" default="false" optional>
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `System.getenv("SECRET_NAME")`.
</ParamField>
<ParamField query="IncludeImports" type="boolean" default="false" optional>
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
</ParamField>
</Expandable>
</ParamField>
### client.GetSecret(options)
```cs
var options = new GetSecretOptions
{
SecretName = "AAAA",
ProjectId = "659c781eb2d4fe3e307b77bd",
Environment = "dev",
};
var secret = infisical.GetSecret(options);
```
Retrieve a secret from Infisical.
By default, `GetSecret()` fetches and returns a shared secret.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretName" type="string" required>
The key of the secret to retrieve.
</ParamField>
<ParamField query="ProjectId" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where secret should be fetched from.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.CreateSecret(options)
```cs
var options = new CreateSecretOptions {
Environment = "dev",
ProjectId = "PROJECT_ID",
SecretName = "NEW_SECRET",
SecretValue = "NEW_SECRET_VALUE",
SecretComment = "This is a new secret",
};
var newSecret = infisical.CreateSecret(options);
```
Create a new secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretName" type="string" required>
The key of the secret to create.
</ParamField>
<ParamField query="SecretValue" type="string" required>
The value of the secret.
</ParamField>
<ParamField query="ProjectId" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where secret should be created.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.UpdateSecret(options)
```cs
var options = new UpdateSecretOptions {
Environment = "dev",
ProjectId = "PROJECT_ID",
SecretName = "SECRET_TO_UPDATE",
SecretValue = "NEW VALUE"
};
var updatedSecret = infisical.UpdateSecret(options);
```
Update an existing secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretName" type="string" required>
The key of the secret to update.
</ParamField>
<ParamField query="SecretValue" type="string" required>
The new value of the secret.
</ParamField>
<ParamField query="ProjectId" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where secret should be updated.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.DeleteSecret(options)
```cs
var options = new DeleteSecretOptions
{
Environment = "dev",
ProjectId = "PROJECT_ID",
SecretName = "NEW_SECRET",
};
var deletedSecret = infisical.DeleteSecret(options);
```
Delete a secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretName" type="string">
The key of the secret to update.
</ParamField>
<ParamField query="ProjectId" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where secret should be deleted.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
## Cryptography
### Create a symmetric key
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
```cs
var key = infisical.CreateSymmetricKey();
```
#### Returns (string)
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
### Encrypt symmetric
```cs
var options = new EncryptSymmetricOptions
{
Plaintext = "Infisical is awesome!",
Key = key,
};
var encryptedData = infisical.EncryptSymmetric(options);
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="Plaintext" type="string">
The plaintext you want to encrypt.
</ParamField>
<ParamField query="Key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (object)
`Tag` (string): A base64-encoded, 128-bit authentication tag.
`Iv` (string): A base64-encoded, 96-bit initialization vector.
`CipherText` (string): A base64-encoded, encrypted ciphertext.
### Decrypt symmetric
```cs
var decryptOptions = new DecryptSymmetricOptions
{
Key = key,
Ciphertext = encryptedData.Ciphertext,
Iv = encryptedData.Iv,
Tag = encryptedData.Tag,
};
var decryptedPlaintext = infisical.DecryptSymmetric(decryptOptions);
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="Ciphertext" type="string">
The ciphertext you want to decrypt.
</ParamField>
<ParamField query="Key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
<ParamField query="Iv" type="string" required>
The initialization vector to use for decryption.
</ParamField>
<ParamField query="Tag" type="string" required>
The authentication tag to use for decryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (string)
`Plaintext` (string): The decrypted plaintext.

View File

@ -1,8 +0,0 @@
---
title: "Go"
icon: "golang"
---
Coming soon.
Star our GitHub repository to stay updated [cross-language SDK](https://github.com/Infisical/sdk) GitHub repository to stay updated.

View File

@ -121,7 +121,7 @@ SecretElement[] secrets = client.listSecrets(options);
Retrieve all secrets within the Infisical project and environment that client is connected to Retrieve all secrets within the Infisical project and environment that client is connected to
### Methods #### Methods
<ParamField query="Parameters" type="object"> <ParamField query="Parameters" type="object">
<Expandable title="properties"> <Expandable title="properties">
@ -165,7 +165,7 @@ Retrieve a secret from Infisical.
By default, `getSecret()` fetches and returns a shared secret. By default, `getSecret()` fetches and returns a shared secret.
### Methods #### Methods
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -203,7 +203,7 @@ CreateSecretResponseSecret newSecret = client.createSecret(createOptions);
Create a new secret in Infisical. Create a new secret in Infisical.
### Methods #### Methods
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -245,7 +245,7 @@ UpdateSecretResponseSecret updatedSecret = client.updateSecret(options);
Update an existing secret in Infisical. Update an existing secret in Infisical.
### Methods #### Methods
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -286,7 +286,7 @@ DeleteSecretResponseSecret deletedSecret = client.deleteSecret(options);
Delete a secret in Infisical. Delete a secret in Infisical.
### Methods #### Methods
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -307,3 +307,76 @@ Delete a secret in Infisical.
</ParamField> </ParamField>
</Expandable> </Expandable>
</ParamField> </ParamField>
## Cryptography
### Create a symmetric key
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
```java
String key = client.createSymmetricKey();
```
#### Returns (string)
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
### Encrypt symmetric
```java
EncryptSymmetricOptions options = new EncryptSymmetricOptions();
options.setKey(key);
options.setPlaintext("Infisical is awesome!");
EncryptSymmetricResponse encryptedData = client.encryptSymmetric(options);
```
#### Methods
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="setPlaintext()" type="string">
The plaintext you want to encrypt.
</ParamField>
<ParamField query="setKey()" type="string" required>
The symmetric key to use for encryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (object)
`tag (getTag())` (string): A base64-encoded, 128-bit authentication tag.
`iv (getIv())` (string): A base64-encoded, 96-bit initialization vector.
`ciphertext (getCipherText())` (string): A base64-encoded, encrypted ciphertext.
### Decrypt symmetric
```java
DecryptSymmetricOptions decryptOptions = new DecryptSymmetricOptions();
decryptOptions.setKey(key);
decryptOptions.setCiphertext(encryptedData.getCiphertext());
decryptOptions.setIv(encryptedData.getIv());
decryptOptions.setTag(encryptedData.getTag());
String decryptedString = client.decryptSymmetric(decryptOptions);
```
#### Methods
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="setCiphertext()" type="string">
The ciphertext you want to decrypt.
</ParamField>
<ParamField query="setKey()" type="string" required>
The symmetric key to use for encryption.
</ParamField>
<ParamField query="setIv()" type="string" required>
The initialization vector to use for decryption.
</ParamField>
<ParamField query="setTag()" type="string" required>
The authentication tag to use for decryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (string)
`Plaintext` (string): The decrypted plaintext.

View File

@ -84,12 +84,12 @@ Import the SDK and create a client instance with your [Machine Identity](/docume
clientSecret: "YOUR_CLIENT_SECRET", clientSecret: "YOUR_CLIENT_SECRET",
logLevel: LogLevel.Error logLevel: LogLevel.Error
}); });
```` ```
</Tab> </Tab>
</Tabs> </Tabs>
### Parameters #### Parameters
<ParamField query="options" type="object"> <ParamField query="options" type="object">
<Expandable title="properties"> <Expandable title="properties">
@ -138,7 +138,7 @@ const secrets = await client.listSecrets({
Retrieve all secrets within the Infisical project and environment that client is connected to Retrieve all secrets within the Infisical project and environment that client is connected to
### Parameters #### Parameters
<ParamField query="Parameters" type="object"> <ParamField query="Parameters" type="object">
<Expandable title="properties"> <Expandable title="properties">
@ -180,7 +180,7 @@ Retrieve a secret from Infisical.
By default, `getSecret()` fetches and returns a shared secret. By default, `getSecret()` fetches and returns a shared secret.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -255,7 +255,7 @@ const updatedApiKey = await client.updateSecret({
Update an existing secret in Infisical. Update an existing secret in Infisical.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -315,3 +315,73 @@ Delete a secret in Infisical.
</ParamField> </ParamField>
</Expandable> </Expandable>
</ParamField> </ParamField>
## Cryptography
### Create a symmetric key
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
```js
const key = client.createSymmetricKey();
```
#### Returns (string)
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
### Encrypt symmetric
```js
const { iv, tag, ciphertext } = await client.encryptSymmetric({
key: key,
plaintext: "Infisical is awesome!",
})
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="plaintext" type="string">
The plaintext you want to encrypt.
</ParamField>
<ParamField query="key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (object)
`tag` (string): A base64-encoded, 128-bit authentication tag.
`iv` (string): A base64-encoded, 96-bit initialization vector.
`ciphertext` (string): A base64-encoded, encrypted ciphertext.
### Decrypt symmetric
```js
const decryptedString = await client.decryptSymmetric({
key: key,
iv: iv,
tag: tag,
ciphertext: ciphertext,
});
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="ciphertext" type="string">
The ciphertext you want to decrypt.
</ParamField>
<ParamField query="key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
<ParamField query="iv" type="string" required>
The initialization vector to use for decryption.
</ParamField>
<ParamField query="tag" type="string" required>
The authentication tag to use for decryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (string)
`plaintext` (string): The decrypted plaintext.

View File

@ -1,8 +0,0 @@
---
title: "PHP"
icon: "php"
---
Coming soon.
Star our GitHub repository to stay updated [cross-language SDK](https://github.com/Infisical/sdk) GitHub repository to stay updated.

View File

@ -60,7 +60,7 @@ client = InfisicalClient(ClientSettings(
)) ))
``` ```
### Parameters #### Parameters
<ParamField query="options" type="object"> <ParamField query="options" type="object">
<Expandable title="properties"> <Expandable title="properties">
@ -110,7 +110,7 @@ client.listSecrets(options=ListSecretsOptions(
Retrieve all secrets within the Infisical project and environment that client is connected to Retrieve all secrets within the Infisical project and environment that client is connected to
### Parameters #### Parameters
<ParamField query="Parameters" type="object"> <ParamField query="Parameters" type="object">
<Expandable title="properties"> <Expandable title="properties">
@ -149,7 +149,7 @@ value = secret.secret_value # get its value
By default, `getSecret()` fetches and returns a shared secret. If not found, it returns a personal secret. By default, `getSecret()` fetches and returns a shared secret. If not found, it returns a personal secret.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -187,7 +187,7 @@ api_key = client.createSecret(options=CreateSecretOptions(
Create a new secret in Infisical. Create a new secret in Infisical.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -225,7 +225,7 @@ client.updateSecret(options=UpdateSecretOptions(
Update an existing secret in Infisical. Update an existing secret in Infisical.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -262,7 +262,7 @@ client.deleteSecret(options=DeleteSecretOptions(
Delete a secret in Infisical. Delete a secret in Infisical.
### Parameters #### Parameters
<ParamField query="Parameters" type="object" optional> <ParamField query="Parameters" type="object" optional>
<Expandable title="properties"> <Expandable title="properties">
@ -283,3 +283,79 @@ Delete a secret in Infisical.
</ParamField> </ParamField>
</Expandable> </Expandable>
</ParamField> </ParamField>
## Cryptography
### Create a symmetric key
Create a base64-encoded, 256-bit symmetric key to be used for encryption/decryption.
```py
key = client.createSymmetricKey()
```
#### Returns (string)
`key` (string): A base64-encoded, 256-bit symmetric key, that can be used for encryption/decryption purposes.
### Encrypt symmetric
```py
encryptOptions = EncryptSymmetricOptions(
key=key,
plaintext="Infisical is awesome!"
)
encryptedData = client.encryptSymmetric(encryptOptions)
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="plaintext" type="string">
The plaintext you want to encrypt.
</ParamField>
<ParamField query="key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (object)
`tag` (string): A base64-encoded, 128-bit authentication tag.
`iv` (string): A base64-encoded, 96-bit initialization vector.
`ciphertext` (string): A base64-encoded, encrypted ciphertext.
### Decrypt symmetric
```py
decryptOptions = DecryptSymmetricOptions(
ciphertext=encryptedData.ciphertext,
iv=encryptedData.iv,
tag=encryptedData.tag,
key=key
)
decryptedString = client.decryptSymmetric(decryptOptions)
```
#### Parameters
<ParamField query="Parameters" type="object" required>
<Expandable title="properties">
<ParamField query="ciphertext" type="string">
The ciphertext you want to decrypt.
</ParamField>
<ParamField query="key" type="string" required>
The symmetric key to use for encryption.
</ParamField>
<ParamField query="iv" type="string" required>
The initialization vector to use for decryption.
</ParamField>
<ParamField query="tag" type="string" required>
The authentication tag to use for decryption.
</ParamField>
</Expandable>
</ParamField>
#### Returns (string)
`plaintext` (string): The decrypted plaintext.

View File

@ -1,8 +0,0 @@
---
title: "Ruby"
icon: "gem"
---
Coming soon.
Star our GitHub repository to stay updated [cross-language SDK](https://github.com/Infisical/sdk) GitHub repository to stay updated.

View File

@ -1,8 +0,0 @@
---
title: "Rust"
icon: "rust"
---
Coming soon.
Star our GitHub repository to stay updated [cross-language SDK](https://github.com/Infisical/sdk) GitHub repository to stay updated.

View File

@ -18,17 +18,8 @@ From local development to production, Infisical SDKs provide the easiest way for
<Card href="/sdks/languages/java" title="Java" icon="java" color="#e41f23"> <Card href="/sdks/languages/java" title="Java" icon="java" color="#e41f23">
Manage secrets for your Java application on demand Manage secrets for your Java application on demand
</Card> </Card>
<Card href="/sdks/languages/ruby" title="Ruby" icon="gem" color="#ac0d01"> <Card href="/sdks/languages/csharp" title="C#" icon="bars" color="#368833">
Manage secrets for your Ruby application on demand Manage secrets for your C#/.NET application on demand
</Card>
<Card href="/sdks/languages/go" title="Golang" icon="golang" color="#00add8">
Manage secrets for your Go application on demand
</Card>
<Card href="/sdks/languages/rust" title="Rust" icon="rust" color="#cd412b">
Manage secrets for your Rust application on demand
</Card>
<Card href="/sdks/languages/php" title="PHP" icon="php" color="#787cb4">
Manage secrets for your PHP application on demand
</Card> </Card>
</CardGroup> </CardGroup>

View File

@ -91,12 +91,14 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: "2592000", accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000", accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0", accessTokenNumUsesLimit: "0",
clientSecretTrustedIps: [{ clientSecretTrustedIps: [
ipAddress: "0.0.0.0/0" { ipAddress: "0.0.0.0/0" },
}], { ipAddress: "::/0" }
accessTokenTrustedIps: [{ ],
ipAddress: "0.0.0.0/0" accessTokenTrustedIps: [
}], { ipAddress: "0.0.0.0/0" },
{ ipAddress: "::/0" }
],
} }
}); });
@ -139,12 +141,14 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: "2592000", accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000", accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0", accessTokenNumUsesLimit: "0",
clientSecretTrustedIps: [{ clientSecretTrustedIps: [
ipAddress: "0.0.0.0/0" { ipAddress: "0.0.0.0/0" },
}], { ipAddress: "::/0" }
accessTokenTrustedIps: [{ ],
ipAddress: "0.0.0.0/0" accessTokenTrustedIps: [
}] { ipAddress: "0.0.0.0/0" },
{ ipAddress: "::/0" }
]
}); });
} }
}, [data]); }, [data]);