mikereinhold: @pdecat - Glad you like the idea!

I've accepted the suggestions you've made above - let me know if there's anything else you see. 

I'll take a look at writing some tests to make sure the output matches the documentation
mikereinhold: @pdecat - Ok, so I improved the expiration by using the value from the AWS session response and reverted the unnecessary datetime changes.

Also through a few unit tests out there to validate that the required values are making it into the json output without being mangled. 
mikereinhold: > Also, the build is failing for most python versions except 3.8-dev: https://travis-ci.org/github/venth/aws-adfs/builds/703676732

It looks like the failures on the older python versions was a combination of building the json via string formatting and how I was grabbing the output via the mock. 

Switched building the json to json.dumps against an object literal and captured the output from click.echo - now tests are passing across all versions
diff --git a/README.md b/README.md
index 38c3e7f..8e24617 100644
--- a/README.md
+++ b/README.md
@@ -166,6 +166,13 @@ aws-adfs integrates with:
     password = your_password
     ```
 
+* .aws/config profile for automatically refreshing credentials
+    ```
+    [profile example-role-ue1]
+    credential_process=aws-adfs login --region=us-east-1 --role-arn=arn:aws:iam::1234567891234:role/example-role --adfs-host=adfs.example.com --stdout
+    ```
+    Warning: see [AWS documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html) about security considerations to take when sourcing credentials with an external process.
+
 * help, help, help?
     ```
     $ aws-adfs --help
diff --git a/aws_adfs/login.py b/aws_adfs/login.py
index 9176b82..7a8302c 100644
--- a/aws_adfs/login.py
+++ b/aws_adfs/login.py
@@ -9,6 +9,7 @@ from os import environ
 import logging
 from platform import system
 import sys
+import json
 from . import authenticator
 from . import prepare
 from . import role_chooser
@@ -232,13 +233,13 @@ def login(
 
 
 def _emit_json(aws_session_token):
-    click.echo(
-        u"""{{"AccessKeyId": "{}", "SecretAccessKey": "{}", "SessionToken": "{}"}}""".format(
-            aws_session_token['Credentials']['AccessKeyId'],
-            aws_session_token['Credentials']['SecretAccessKey'],
-            aws_session_token['Credentials']['SessionToken']
-        )
-    )
+    click.echo(json.dumps({
+        "Version": 1,
+        "AccessKeyId": aws_session_token['Credentials']['AccessKeyId'],
+        "SecretAccessKey": aws_session_token['Credentials']['SecretAccessKey'],
+        "SessionToken": aws_session_token['Credentials']['SessionToken'],
+        "Expiration": aws_session_token['Credentials']['Expiration'].isoformat()
+    }))
 
 def _print_environment_variables(aws_session_token,config):
     envcommand = "export"

integration to aws credential_process
Hi, 

I am trying to integrate to AWS CodeCommit. Whenever the user performs a git pull, it would authenticate with AD FS and STS and use the token to access CodeCommit. I would seek your help on this implementation.

Unfortunately, I have tried a few commands but i could not get it working

This is the configuration i have set inside my .aws/config file. I have also tried without --stdout but to no avail

[profile adfs]
credential_process = aws-adfs login --adfs-host adfs.host.com --provider-id urn:amazon:webservices --role-arn arn:aws:iam::123456789098:role/AWS_ROLE --no-ssl-verification --profile adfs --region eu-central-1 --session-duration 3600 --stdout

.gitconfig:
	helper = !aws --profile adfs codecommit credential-helper $@
diff --git a/test/test_credential_process_json.py b/test/test_credential_process_json.py
new file mode 100644
index 0000000..3d34b90
--- /dev/null
+++ b/test/test_credential_process_json.py
@@ -0,0 +1,41 @@
+import datetime
+import json
+from aws_adfs import login
+from mock import patch
+
+
+class TestCredentialProcessJson:
+
+    def setup_method(self, method):
+        self.access_key = 'AKIAIOSFODNN7EXAMPLE'
+        self.secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY'
+        self.session_token = 'AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA=='
+        self.expiration = datetime.datetime(2020,6,20)
+
+        self.aws_session_token = {
+            'Credentials': {
+                'AccessKeyId': self.access_key,
+                'SecretAccessKey': self.secret_key,
+                'SessionToken': self.session_token,
+                'Expiration': self.expiration
+            }
+        }
+
+    capture = ''
+    def _replace_echo(self, value):
+        self.capture = value
+
+    def test_json_is_valid_credential_process_format(self):
+        with patch('click.echo', side_effect = self._replace_echo):
+            login._emit_json(self.aws_session_token)
+
+            result = json.loads(self.capture)
+            print(result)
+
+            # Version is currently hardlocked at 1, see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html
+            assert result["Version"] == 1
+            assert result["AccessKeyId"] == self.access_key
+            assert result["SecretAccessKey"] == self.secret_key
+            assert result["SessionToken"] == self.session_token
+            # Expiration must be ISO8601, see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html
+            assert result["Expiration"] == self.expiration.isoformat()

pip install -e .[test]
parse_log_pytest
pytest
pytest pytest-runner mock coverage
apt-get update apt-get install -y gcc
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///croot/attrs_1668696182826/work
-e git+https://github.com/venth/aws-adfs.git@39a5767e8c34a520e66870099eb5d41c1fb14de5#egg=aws_adfs
botocore==1.33.13
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
click==8.1.8
configparser==5.3.0
coverage==3.7.1
cryptography==44.0.2
decorator==5.1.1
fido2==0.8.1
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
gssapi==1.8.3
idna==3.10
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1648562407465/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
jmespath==1.0.1
krb5==0.6.0
lxml==5.3.1
mock==5.2.0
packaging @ file:///croot/packaging_1671697413597/work
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pycparser==2.21
pyspnego==0.9.2
pytest==7.1.2
pytest-runner==6.0.1
python-dateutil==2.9.0.post0
requests==2.31.0
requests-kerberos==0.15.0
six==1.17.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions @ file:///croot/typing_extensions_1669924550328/work
urllib3==1.26.20
zipp @ file:///croot/zipp_1672387121353/work

name: aws-adfs
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib-metadata=4.11.3=py37h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - botocore==1.33.13
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - configparser==5.3.0
      - coverage==3.7.1
      - cryptography==44.0.2
      - decorator==5.1.1
      - fido2==0.8.1
      - gssapi==1.8.3
      - idna==3.10
      - jmespath==1.0.1
      - krb5==0.6.0
      - lxml==5.3.1
      - mock==5.2.0
      - pycparser==2.21
      - pyspnego==0.9.2
      - pytest-runner==6.0.1
      - python-dateutil==2.9.0.post0
      - requests==2.31.0
      - requests-kerberos==0.15.0
      - six==1.17.0
      - urllib3==1.26.20
prefix: /opt/conda/envs/aws-adfs

test/test_credential_process_json.py::TestCredentialProcessJson::test_json_is_valid_credential_process_format
aws_adfs/login.py README.md
aws_adfs/login.py README.md