Skip to content

slick auth

Manage Slack authentication. Login validates a token with Slack and stores a structured credential reference in the local keychain. Config holds the keychain reference; it never holds a raw token.

slick auth login    Create a workspace profile (OAuth or token)
slick auth status   Show auth status for every configured workspace
slick auth switch   Switch the default workspace
slick auth logout   Remove workspace credentials

auth login

Create or replace a workspace profile.

The local profile name can come from either flag: the hidden --workspace-name <NAME> (preferred) or the global --workspace <NAME> selector — if --workspace-name is empty, slick reuses the value of --workspace. On a TTY, omitting both drops into an interactive form that prompts for the missing fields.

For token mode, slick calls Slack's auth.test after validating the token and fills in team_id / team_name from the response. Pass --team-id / --team-name only if you need to override what Slack returns (rare).

# Interactive — TTY only. Prompts for workspace name, method, and
# whatever else is missing.
slick auth login

# OAuth, fully scripted. --workspace-name and --oauth-client-id are
# required; --oauth-callback-port must match the redirect URL in your
# manifest.
slick auth login --workspace-name default --method oauth \
    --oauth-client-id 1234567890.0987654321 \
    --oauth-callback-port 53221

# Token via stdin (token never appears in argv). slick derives the
# workspace identity from auth.test.
printf '%s\n' "$SLACK_TOKEN" | slick auth login \
    --workspace-name default --method token --token-stdin

# Token from a file (path expansion supported):
slick auth login --workspace-name default --method token \
    --token-file ~/.slack-token

# Token from a named environment variable (the name, not the value):
slick auth login --workspace-name default --method token \
    --token-env SLACK_TOKEN

Output

Human (success — same shape for OAuth and token-mode logins; both end with a single Login complete event on stdout):

Login complete workspace=default team_id=T123ABC456 team_name="Example Inc" token_type=user authenticated=true

Human (token env var unset or empty — validation error):

ERR token environment variable SLACK_TOKEN is empty type=validation_error exit_code=4

JSON envelope on a successful login (auth.login):

{
  "meta": {"command": "auth.login", "workspace": "default", "timestamp": "…", "request_id": "…"},
  "data": {
    "workspace": "default",
    "authenticated": true,
    "token_type": "user",
    "team_id": "T123ABC456",
    "team_name": "Example Inc"
  },
  "errors": []
}

Flags

    --workspace-name <NAME>        Local profile name. Hidden in --help.
                                   Falls back to the global --workspace
                                   value when omitted.
-s, --token-stdin                  Read Slack token from stdin
-f, --token-file <FILE>            Read Slack token from file
-e, --token-env <VAR>              Read Slack token from named environment variable
-T, --team-id <ID>                 Slack workspace ID (overrides auth.test)
-N, --team-name <NAME>             Slack workspace display name (overrides auth.test)
-m, --method <METHOD>              Auth mechanism: oauth or token (default: token)
-C, --oauth-client-id <ID>         Slack OAuth client ID
-r, --oauth-redirect-url <URL>     Slack OAuth redirect URL configured on the app
-p, --oauth-callback-port <PORT>   Local OAuth callback port; 0 for OS-assigned
-F, --force                        Overwrite an existing authenticated profile

The profile-name resolution order is: --workspace-name flag, then the global --workspace flag value, then the TTY interactive form. After those, slick errors with workspace-name is required if it still doesn't have one.

For token mode, slick calls auth.test after the token validates and fills team_id / team_name from the response. Pass --team-id / --team-name only when you need to override what Slack returns.

OAuth flow

  1. slick opens the Slack authorize URL in the default browser and listens on the configured local port.
  2. The Slack consent screen redirects back to http://localhost:<port>/callback.
  3. slick exchanges the code for a token, stores it in the keychain, and writes a token_ref to the config TOML.

During the wait, a spinner displays the authorize URL on stderr so you can copy it if the browser launch fails. Ctrl-C cancels the wait. The default OAuth-wait budget is two minutes (OAuthTimeout); the token-exchange POST gets its own fresh per-request budget.

Common errors

Error Cause Fix
workspace profile is already authenticated; rerun with --force to overwrite auth fields Profile metadata + keychain credential both exist. Pass --force to overwrite. The guard checks the keychain too, so a profile whose credential is gone (e.g. keychain reset) does not trip it.
oauth flow timed out waiting redirect_url=… The OAuth window stayed open longer than OAuthTimeout (default 2m). Re-run; consider raising OAuthTimeout if your IdP redirect is slow.
invalid_auth / token_revoked Token is bad or has been revoked on Slack's side. Re-run auth login.

auth status

Show auth state for every configured workspace. The action label colour-codes state at a glance:

  • Authenticated (bold green) — credentials valid; authenticated=true.
  • Authentication invalid (red) — credentials exist but Slack rejected them.
  • Credentials missing (red) — workspace metadata exists; no credential in the keychain.
slick auth status

Human output:

Authenticated workspace=default team_id=T123ABC456 team_name="Example Inc" token_type=user authenticated=true

JSON envelope (authenticated profile):

{
  "data": {
    "workspaces": [
      {
        "workspace": "default",
        "authenticated": true,
        "token_type": "user",
        "team_id": "T123ABC456",
        "team_name": "Example Inc",
        "validation_state": "valid"
      }
    ]
  }
}

JSON envelope (workspace metadata intact but no credential — the state after a destructive auth logout). validation_state flips from valid to missing and authenticated becomes false:

{
  "data": {
    "workspaces": [
      {
        "workspace": "default",
        "authenticated": false,
        "token_type": "user",
        "team_id": "T123ABC456",
        "team_name": "Example Inc",
        "validation_state": "missing"
      }
    ]
  }
}

auth switch

Change the default workspace selected by --workspace.

slick auth switch <workspace>

Pass the workspace key as it appears in slick workspace list. Whitespace in the argument is trimmed; --debug logs the trim.

Output

Human:

Workspace switched workspace=default authenticated=false

The trailing authenticated=false is a code-side quirk: switch only sets the workspace name on its result record, and authenticated is the only field on the shared WorkspaceData struct without omitempty, so its zero value leaks into the event. It is not an assertion that the profile is unauthenticated.

JSON envelope (auth.switch). switch only populates workspace; the other identity fields are omitempty and absent here. authenticated is the lone non-omitempty field on the struct, so it always emits — its false value is a leakage of the zero state, not an assertion about the profile's auth status:

{
  "data": {
    "workspace": "default",
    "authenticated": false
  }
}

auth logout

Revoke the token on Slack and delete the local credential. With --keep-token, slick removes the workspace's auth fields from config but leaves the keychain credential alone and skips Slack-side revocation.

slick auth logout <workspace>
slick auth logout default --keep-token

Flags

-K, --keep-token  Skip token revocation and local credential deletion; only
                  removes the workspace auth fields from config

--keep-token emits an Info-level notice on stderr explaining that the token remains valid on Slack until manually revoked or it expires.

Output

Human (destructive logout — revokes on Slack, deletes the keychain entry):

Logout complete workspace=default authenticated=false

Human (--keep-token). The first line is the Info-level notice on stderr; the second is the result event on stdout:

INF --keep-token preserves the credential in keychain; the token is still valid on Slack's side until manually revoked or it naturally expires workspace=default
Logout complete workspace=default authenticated=false

Behaviour caveat

--keep-token documents itself as "removes the workspace auth fields from config." In practice, a subsequent auth status still resolves the workspace successfully because the credential remains in the keychain and status falls back to validating via auth.test. If you want auth status to actually report the profile as missing, use the destructive logout (without --keep-token).

JSON envelope (auth.logout). authenticated is forced to false:

{
  "data": {
    "workspace": "default",
    "authenticated": false
  }
}

See also