NAME

ecs_token - Use OAuth 2.0 refresh token to get new access token

SYNOPSIS

ecs_token code
(use web browser to log in to EMDIS email account)
(open displayed URL in web browser and follow flow to get auth code)
(paste auth code at input prompt)

ecs_token credentials

ecs_token refresh

DESCRIPTION

ecs_token offers support for obtaining an OAuth 2.0 access token. A valid OAuth 2.0 access token is needed when connecting to email services that require "modern" SASL XOAUTH2 or OAUTHBEARER authentication.

When successful, the output of the non-interactive ecs_token credentials and ecs_token refresh commands match the requirements of the INBOX_OAUTH_TOKEN_CMD and SMTP_OAUTH_TOKEN_CMD configuration settings for EMDIS::ECS.

To securely store the client id, client secret, refresh token and related parameters, ecs_token uses the pass (passwordstore.org) command-line password manager, which stores its data in gpg-encrypted files.

Note: Due to variations in OAuth 2.0 identity provider setup requirements and implementation details, this ecs_token program may not be directly usable with all identity providers.

OPTIONS

Usage

ecs_token <command> [options]

Commands

Each command implements a different OAuth 2.0 flow.

code

Use authorization code flow to request new OAuth 2.0 access token and refresh token. Displays URL for user to visit in web browser to log in and give consent. Waits for user to enter authorization code, then uses code to request an access token. Stores new refresh token from response to token request.

credentials

Use client credentials flow to request new OAuth 2.0 access token.

refresh

Use existing refresh token to request new OAuth 2.0 access token. Store new refresh token if present in response to token request.

Configuration Parameters

Configuration parameter values can be set by storing the value in secure storage or by passing the value on the ecs_token command line.

Example using pass secure storage:

echo -n 'https://accounts.google.com/o/oauth2/auth' | \
  pass insert --echo emdis/ecs/oauth/auth_endpoint

Example using command line parameter:

ecs_token code --auth_endpoint https://accounts.google.com/o/oauth2/auth
auth_endpoint

OAuth 2.0 authorization code endpoint, for authorization code flow. Required by the ecs_token code command. Example value:

https://accounts.google.com/o/oauth2/auth
cached_token_response

Not a true configuration parameter, but only a secure storage location to hold a copy of the most recent token response, so it can be reused until it expires. To avoid a secure storage retrieval error, initialize this to the value '' (empty string).

cached_token_timestamp

Not a true configuration parameter, but only a secure storage location to hold a timestamp for the most recent token response. To avoid a secure storage retrieval error, initialize this to the value '0' (zero).

client_id

OAuth 2.0 client id. Required by the ecs_token code, ecs_token credentials, and ecs_token refresh commands. Example value:

1083558311832-0q5ul7ffdg6n4fj1p1to6rae88hvhsha.apps.googleusercontent.com
client_secret

OAuth 2.0 client secret. Required by the ecs_token code, ecs_token credentials, and ecs_token refresh commands. Example value:

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
nocache

This flag can only be set via the command line, not via secure storage. When nocache is set, the program will not attempt to retrieve a cached access token from storage or cache a new access token for future use.

redirect_uri

OAuth 2.0 redirect URI, for authorization code flow. Required by the ecs_token code command. Example value:

https://google.github.io/gmail-oauth2-tools/html/oauth2.dance.html
refresh_token

OAuth 2.0 refresh token, for refresh token flow. Required by the ecs_token refresh command. Initialized by the ecs_token code command. May also be populated by the ecs_token refresh command. Example value:

1//04Gei0xdQmoxKCgYIARAAGAQSNwF-L9IrizgSeuBmjQf7RNSPpAKUK-wsOFcDicS8jZEmusXSppx09bFyehICh4WkGqRrUj73OH0
scope

OAuth 2.0 scope. Required by the ecs_token code and ecs_token credentials commands. Example values:

https://mail.google.com/
https://outlook.office365.com/.default
token_endpoint

OAuth 2.0 token endpoint. Required by the ecs_token code, ecs_token credentials, and ecs_token refresh commands. Example values:

https://accounts.google.com/o/oauth2/token
https://login.microsoftonline.com/[tenant_id]/oauth2/v2.0/token

SETUP

GnuPG

See also https://gnupg.org/ for additional details about GnuPG.

  1. Start gpg-agent with --allow-preset-passphrase option. E.g.:

    gpg-agent --homedir /home/perlecs/.gnupg --daemon \
      --allow-preset-passphrase

    The allow-preset-passphrase option can also be specified in a gpg-agent.conf configuration file.

  2. Find the keygrip for the selected key.

    gpg --list-keys --with-keygrip
  3. Use the keygrip to preset the key's passphrase in the gpg-agent cache.

    echo -n '<gpg_passphrase>' | \
      /usr/libexec/gpg-preset-passphrase --preset <gpg_keygrip>

pass

See also https://www.passwordstore.org/ for additional details about pass.

  1. Find the fingerprint for the selected key.

    gpg --list-keys
  2. Initialize password storage using the selected key.

    pass init <gpg-key-fingerprint>
  3. Populate the expected secure storage locations with information needed by ecs_token. E.g.:

    echo -n 'https://accounts.google.com/o/oauth2/auth' | \
      pass insert --echo emdis/ecs/oauth/auth_endpoint
    
    echo -n '' | \
      pass insert --echo emdis/ecs/oauth/cached_token_response
    
    echo -n '0' | \
      pass insert --echo emdis/ecs/oauth/cached_token_timestamp
    
    echo -n '<client_id>' | \
      pass insert --echo emdis/ecs/oauth/client_id
    
    echo -n '<client_secret>' | \
      pass insert --echo emdis/ecs/oauth/client_secret
    
    echo -n 'https://google.github.io/gmail-oauth2-tools/html/oauth2.dance.html' | \
      pass insert --echo emdis/ecs/oauth/redirect_uri
    
    echo -n '<refresh_token>' | \
      pass insert --echo emdis/ecs/oauth/refresh_token
    
    echo -n 'https://mail.google.com/' | \
      pass insert --echo emdis/ecs/oauth/scope
    
    echo -n 'https://accounts.google.com/o/oauth2/token' | \
      pass insert --echo emdis/ecs/oauth/token_endpoint

Gmail Setup Notes

The following are notes on setting up an app and getting an OAuth 2.0 access token for use with Gmail SMTP/IMAP/POP3.

  1. Download oauth2.py from GitHub. See comments in script for additional info.

    https://github.com/google/gmail-oauth2-tools/blob/master/python/oauth2.py

  2. In a web browser, log in to the Google account that will be using Gmail.

    https://accounts.google.com

  3. Define the OAuth 2.0 client id and client secret to be used by the Perl ECS app.

    1. Go to Google developers console.

      https://console.developers.google.com

    2. If needed, create a project. In Google Cloud console, select Navigation menu (three horizontal bars in upper left corner of page) > IAM & Admin > Create a Project. On New Project page, enter Project name and select Location, then click Create button.

    3. Select the applicable project. In Google Cloud console, click the Open project picker button (next to Google Cloud logo at top of page), then, in the Select a project popup, click the link for the project.

    4. Configure OAuth settings for the new project. In Google Cloud console, select Navigation menu > APIs & Services > OAuth consent screen. On the OAuth Overview page, click the Get started button. On the Project configuration page, under App Information enter the App name and User support email, and click the Next button. Under Audience select External and click the Next button. Under Contact information enter Email addresses and click the Next button. Under Finish click the I agree ... checkbox and click the Continue button. Then, click the Create button.

    5. Create OAuth 2.0 client ID for Perl ECS app. In Google Cloud console, select Navigation menu > APIs & Services > Credentials. On the Credentials page, click the + Create credentials button and select OAuth client ID from the drop-down menu. On the Create OAuth client ID page select Web application as the Application type and enter an appropriate name for the app (e.g. "Perl ECS"). Under Authorized redirect URIs click the + Add URI button and enter the following URI (as mentioned in the oauth.py script):

      https://google.github.io/gmail-oauth2-tools/html/oauth2.dance.html

      Then, click the Create button.

      From the OAuth client created popup, make note of the Client ID and Client secret. Click OK.

    6. Allow a few minutes for the settings to take effect.

  4. Add the email account as a test user for the project. In Google Cloud console, select Navigation menu > APIs & Services > OAuth consent screen, then select Audience. On the Audience page, under Test users click the + Add users button. In the Add users panel enter the test user's email address (e.g. xyz@gmail.com) and click the Save button.

  5. Use oauth2.py script to generate and authorize an OAuth 2 token. See also comments in script. E.g.:

    python3 oauth2.py --user=xyz@gmail.com \
      --client_id=1038[...].apps.googleusercontent.com \
      --client_secret=VWFn8LIKAMC-MsjBMhJeOplZ \
      --generate_oauth2_token

    To authorize the token, use a web browser to visit the URL indicated by the script and follow the browser-based authorization flow. At the script's Enter verification code prompt, enter the authorization code displayed in the web browser. If successful, the script displays a Refresh Token and Access Token.

    If the browser authorization flow results in an error saying "Access blocked: google.github.io has not completed the Google verification process", add the email account as a test user for the project (see above) and reload the URL provided by the oauth2.py script.

  6. Use oauth2.py script to test SMTP authentication. E.g.:

    python3 oauth2.py --user=xxx@gmail.com \
      --access_token=ya29.a0A[...]0175 \
      --test_smtp_authentication
  7. Use oauth2.py script to test IMAP authentication. E.g.:

    python3 oauth2.py --user=xxx@gmail.com \
      --access_token=ya29.a0A[...]0175 \
      --test_imap_authentication
  8. Use oauth2.py script to obtain a new access token, using a refresh token. E.g.:

    python3 oauth2.py \
      --client_id=1038[...].apps.googleusercontent.com \
      --client_secret=VWFn8LIKAMC-MsjBMhJeOplZ \
      --refresh_token=1//04[...]anrA

RETURN VALUE

Returns a non-zero exit code if an error is encountered.

SEE ALSO

EMDIS::ECS::Config, https://gnupg.org/, https://www.passwordstore.org/, https://oauth.net/2/, https://datatracker.ietf.org/doc/html/rfc6749

AUTHOR

Joel Schneider <jschneid@nmdp.org>

COPYRIGHT AND LICENSE

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

Copyright (C) 2025 National Marrow Donor Program. All rights reserved.

See LICENSE file for license details.

HISTORY

ECS, the EMDIS Communication System, was originally designed and implemented by ZKRD (https://zkrd.de/). This Perl implementation of ECS was developed by NMDP (https://nmdp.org/).