Prerequisites
Prerequisites
Complete one of:
- Connect AWS Account (account-mode users)
- Deploy Organisation (organisation-mode users)
Overview
Authentication and the choice of which AWS account a deploy lands in are two separate concerns. Neither is driven by a manual profile step, and neither is stored infjall-config.json.
fjall login writes your Fjall credential to ~/.fjall/auth.json (or $FJALL_CONFIG_DIR/auth.json). For the management account, and for any other account that carries its own OIDC role, it is the only credential you supply: Fjall derives that account’s AWS credentials from it. A command run against an organisation member account with no OIDC role of its own gets that account’s credentials from AWS IAM Identity Center instead, through a sign-in you make in your browser (see SSO re-authentication). fjall org deploy reaches the member accounts it cascades to by assuming OrganizationAccountAccessRole from the management account’s session, and fjall unlock bucket --account reaches one through STS AssumeRoot from that session. When both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set, a command that derives a target’s credentials uses those keys instead (see Environment credentials override derivation). fjall unlock bucket, and the reads fjall domain delegate and fjall domain sync make in other accounts, never take them: they always sign in with the organisation’s own profiles.
There is no
fjall profile command. Fjall never writes ~/.aws/config or ~/.aws/credentials, but the AWS SDK can still read a profile from them, such as the one an exported AWS_PROFILE names (see The AWS SDK can still read your AWS profiles). aws sso login is not part of the flow.Authentication modes
Both modes derive from the same organisation config, which Fjall fetches from the API (GET /api/organisation-config, cached for five minutes).
Account mode. You connected a single AWS account with fjall connect. The account carries its own OIDC role, so Fjall mints a token from the Fjall API and calls STS AssumeRoleWithWebIdentity against that role.
Organisation mode. You scaffolded a multi-account organisation with fjall create organisation and deployed it with fjall org deploy, which resolves the IAM Identity Center instance you enabled in the console. Member accounts that have no OIDC role of their own authenticate through SSO.
OIDC applies whenever an account carries its own oidcRoleArn, including the pre-org deploy state right after Quick Create. SSO applies to organisation members that lack one.
How profiles are derived
deriveProfiles(orgConfig) is a pure, in-memory derivation. Three arms cover every account.
The region abbreviation collapses an AWS region to a short token:
us-east-1 becomes use1, us-east-2 becomes use2, eu-west-1 becomes euw1.
SSO profiles use the AdministratorAccess role and the sso-<rootname> session resolved from your organisation config.
Environment credentials override derivation
Authentication reads the process environment before any derivation runs. When bothAWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set, Fjall uses those credentials directly under the profile name environment-credentials and returns. AWS_SESSION_TOKEN is used when present.
The region is still resolved separately, from -r, --region first, then AWS_REGION, then AWS_DEFAULT_REGION, then us-east-2. Fjall validates the supplied keys with STS GetCallerIdentity before returning them, so expired keys fail at authentication rather than part-way through a deploy.
The AWS SDK can still read your AWS profiles
Fjall never writes~/.aws/config or ~/.aws/credentials, and the credentials it derives for a target never come from them. It does pass AWS_PROFILE from your shell to the CDK CLI it runs, because your infrastructure.ts may read it. Where Fjall gives the AWS SDK no credentials of its own, the SDK looks for credentials itself, and can take them from a profile in those files, such as the one AWS_PROFILE names or the default profile.
fjall validate --deep --synth, for example, runs the CDK CLI with no credentials. Unless your shell sets both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, the CDK CLI then takes its credentials from a profile in those files when it finds one, and that profile’s account becomes the default account of the stacks the synth produces. Unset AWS_PROFILE first, or point it at a profile for the account you deploy to. With it unset, the CDK CLI can still take the default profile’s credentials.
The check of the CDK bootstrap stack that fjall deploy, fjall org deploy, fjall platform deploy and fjall account deploy make before they bootstrap their target account also gives the AWS SDK no credentials. With AWS_PROFILE set, the check reads the stack with that profile’s credentials, in the profile’s account, rather than with the credentials the deploy runs with. The bootstrap itself still runs with the deploy’s own credentials. Unset AWS_PROFILE before you deploy, or point it at a profile for the account you deploy to. With it unset, the check uses the deploy’s own credentials.
Inspecting derived profiles
Profiles are computed at run time and never written to disk, soaws configure list-profiles returns nothing about Fjall. Inspect the derived accounts and regions through the CLI instead:
~/.aws is the SSO token cache at ~/.aws/sso/cache, which holds a short-lived token rather than any profile definition.
SSO re-authentication
When an organisation-mode SSO token has expired, Fjall runs the SSO device-authorisation flow at deploy time and opens your browser. A cached, valid token prints nothing at all. In--non-interactive runs the URL is printed for you to open:

Selecting a deployment target
A target is an account and region pair, named<accountname>-<regionabbrev>, for example production-use1 or development-euw1. Targets are derived by crossing every non-organisation-tier account with your organisation’s configured regions (primary, secondary and disaster recovery). Root accounts are excluded.
fjall target list prints one row per target with its environment, account and region, marks the active target with ▸, and closes with an Active: <name> line. A row may carry a readiness annotation too: ✓ ready, or ! not ready — <reason> when the target cannot be deployed to yet. Rows whose readiness was not probed carry no annotation.
Where the active target is stored
fjall target set writes activeTarget to .fjall/local.json, a git-ignored file beside fjall-config.json. The active target is per developer and per checkout, so a colleague’s choice or a CI pipeline never inherits yours.
Options for fjall target set
fjall target set refuses in four cases:
- You are not signed in to Fjall.
- You are outside any Fjall project and did not pass
--create-config. - The project’s
organisationbinding names a different organisation from your current credential. - The target’s region is not one of your organisation’s configured regions.
-y, --yes.
How the deploy account is resolved
At deploy time Fjall walks one precedence chain and fails closed at the end.--target <name>on the command. An unknown name is a hard error listing the valid targets, never a silent fallback.activeTargetfrom.fjall/local.json.- Auto-select when exactly one target exists, or the root profile when no targets exist. The tier deploys count differently:
fjall account deployauto-selects when the organisation has exactly one member account, so a single account spanning two regions still resolves without a prompt. - Refuse, listing the candidate targets and pointing at
fjall target set.
--target fails closed on the commands listed below. The name decides which account Fjall mints credentials for, so the resolution refuses every cached fallback the ordinary read would accept. An organisation config cached in the last five minutes still answers the config read, but the identity read in front of it is always live, so an unreachable API refuses the command however fresh that copy is.
The refusal reads Failed to fetch organisation config: <cause>. Fjall stops there rather than resolving the target from a copy that may name the account it used to point at.
The same posture covers --target on fjall deploy, fjall destroy, fjall aws exec, every fjall secret leaf, fjall domain deploy, fjall domain sync, fjall domain verify and fjall migrate identity. fjall apps create --target and fjall create application --target already refused a stale read before 38, with a message naming the target they could not check. fjall ci run resolves its target the same way and never falls back to an active target.
Steps 2 to 4, the ambient active-target chain, are unchanged. They still accept a stale cached config when the API is unreachable.
The tier deploys sit outside this posture. fjall org deploy and fjall org destroy reject --target outright, because organisation infrastructure always lands in the management account. fjall account deploy --target and fjall account destroy --target are stricter again, reading the organisation config fresh from the API on every run.
fjall platform deploy --target and fjall platform destroy --target keep the ordinary read. They check that the name resolves to the platform account, but the config behind that check can be a stale cached copy when the API is unreachable.
-r, --region overrides the region within the resolved target’s account.
The positional argument to fjall deploy is the application name, not a target:
Tier deploys are noun-verb:
fjall org deploy, fjall platform deploy, fjall account deploy. Passing a tier word to fjall deploy fails before authentication with a teaching error.The environment flag is not a target selector
fjall deploy accepts -e, --environment <env>, but it selects no account, no region and no target.
.env.<stage> Docker build-arg tier during the image build. Treat it as a CI build-arg label.
The environment that actually drives synthesis (and therefore every removal policy) comes from the target account’s own record, not from a flag. Fjall resolves it from your organisation config, uses root for the organisation tier and the account’s recorded stage otherwise, then passes it to CDK as both ENVIRONMENT= and -c environment=. A deploy fails closed if that value cannot be resolved.
A second, unrelated -e, --environment exists on fjall account deploy. It is constrained to production, staging, development, platform and compliance, and it stamps the workload stage recorded for a standalone account registration. Fjall rejects it for an account that already belongs to an organisation. The same vocabulary appears on fjall connect --environment.
What fjall-config.json contains
fjall-config.json is the committed project marker. Its strict write schema declares exactly four optional keys.
deploy mapping, no environments block, no stage field and no account or region mapping of any kind. Accounts, regions, OIDC role ARNs and SSO sessions live in your organisation config, which Fjall fetches from the API and injects into the deploy.
Next Steps
Deploy Platform
Deploy your platform account in organisation mode.
Deploy Application
Deploy an application to your selected target.
Deploy Organisation
Set up a multi-account organisation.
Connect AWS Account
Connect a single account in account mode.