Attachment 03 FAMAuth Developer Guide.pdf

PDF 1 MB Posted

Attached to
Aircraft Computer Maintenance Management System
Solicitation number
12760426Q0005-2
Issued by

About this file

This document is a FAMAuth (Fire and Aviation Management Authentication and Authorization) Portal Web Application Integration Guide that provides technical documentation for developers integrating client applications with the FAMAuth authentication service. Release 2.9, Revision 022, dated June 3, 2024.

FAMAuth is an interagency wildland fire authentication portal that authenticates government users via USDA eAuthentication and non-government users via Login.gov, with optional SAML federation bridging for other agencies such as the Department of Interior. The portal currently supports web server applications only and uses the OAuth 2.0 protocol for delegated authorization. Client applications integrating with FAMAuth must implement six core steps: invoking the client application, redirecting the browser to the FAMAuth authorization server, receiving an authorization code, posting the authorization code to acquire an access token, receiving the access token response, and issuing a GET request with the access token to retrieve the authenticated user profile. An optional component called FAMAuth Admin holds entitlements for wildland fire application users, allowing them to request access, roles, and approvals from application representatives. To register a client application, developers must contact the FAMIT point of contact (Ryan Hunt) and provide application details including short name, long name, description, application URL, agency, optional image, and indication of FAMAuth Admin usage. The FAMAuth team will then provide the client ID and client secret necessary for OAuth2 integration. The guide includes sample code implementations in Java, .NET, and Spring Boot, along with detailed technical specifications for API endpoints, request/response formats, and user experience workflows with FAMAuth Admin for authorization and access management.

View the file

Other files

Show all 12

On GovTribe

Work with this file

  • Download the original file
  • Contacts named in this file
  • Similar government files
  • Ask GovTribe AI about this file

Text version

FAMAuth Portal Web Application Integration Guide

Interagency Wildland Fire Incident Response

Portal

Access & Authentication Service

FAMAuth Developer Guide

Release 2.9

Rev #022

Table of Contents

Overview

FAMAuth Portal with eAuthentication, Login.gov and FAMAuth Admin

Get Started: Registering a Client Application

USDA eAuthentication Integration Overview

GSA Login.gov Integration Overview

Implementation: Login to the FAMAuth Portal

Part 1 - Authenticating with Service Provider (eAuthentication or Login.gov)

Part 2 – Client Web Application Integration – 6 Steps

STEP 1 – Invoke Client Application

STEP 2 – Browser Redirect to FAMAuth Authorization Server

STEP 3 – Authorization code returned from FAMAuth

STEP 4 – Authorization Code Posting for Acquiring Access Token

STEP 5 – The FAMAuth Response to Client Posting is an Access Token

STEP 6 - Issuing a GET with the Access Token for the authenticated user profile retrieval

STEP 7 – Browser Redirect to FAMAuth Admin (if using FAMAuth Admin) and Unauthorized User

Appendix A: Web App Examples Integrating with the Authentication Service

A. Java Client App Sample Code, Authenticating Users with FAMAuth

B. .NET Client App Sample Code, Authenticating Users with FAMAuth

C. Spring Boot Client App Sample Code, Authenticating Users with FAMAuth

Appendix B: User Experience with FAMAuth Admin

Frequently Asked Questions (FAQs)

Revision History

Rev # Date Author Description

000 4/30/2021 EAD Team Initial Revision

001 7/8/2021 Julie Olson Incorporated changes from FAMAuth 2.0 release: Add instructions for applications using iNAP for authorization.

002 7/22/2021 Mike Roadifer Updated FAMIT point of contact to Ryan Hunt.

003 9/14/2021 Julie Olson Fixed iwfirp URLs from Dev to QA.

Updated Login page snapshot.

004 10/2/2021 Dan Gropp FAMAuth 2.1 Updated /me service responses, /token service screens shots, add information about the /meta service that can be used to auto configure an OAUTH2 application and added a FAQ to the appendix on how to book mark an application.

005 11/5/2021 Julie Olson Updated the FAMAuth screen shots for 2.1 release.

006 11/22/2021 Mike Roadifer Updated to consistently reference as FAMAuth.

Corrected exchange between FAMAuth and client application as simply OAuth2. Added interaction with iNAP.

007 2/1/22 Julie Olson Added FAMAuth/iNAP user experience flowchart in appendix B.

008 5/2/22 Julie Olson Updated the FAMAuth screen shots for 2.2 release.

009 5/31/22 Dan Gropp Added user_authenticated_by for Neil @AFF to the /me service in the 2.3 release.

010 8/16/22 Julie Olson Updated the FAMAuth screen shots for 2.3 release.

011 10/27/22 Michelle Apicella Updated FAMAuth screen shots for 2.4 release.

012 10/27/22 Dan Gropp Added description of refresh token in FAQ.

013 10/28/22 Julie Olson Updated FAMAuth/iNAP flow chart for iNAP 2.7 release.

014 12/13/22 Dan Gropp Updated iNAP user authorization returned output for iNAP 2.8 release

015 11/6/23 Dan Gropp Added how a client application can call FAMAuth’s logout service.

016 12/7/23 Mike Roadifer Updated for migration to famauth-qa.wildfire.gov.

017 12/7/23 Julie Olson Updated screen shots for 2.8 release.

018 1/29/24 Dan Gropp Added comments to describe appending a client application redirection URL parameter to the returned napRedirectURL

019 1/31/24 Julie Olson Added an explanation of the benefit of appending the

CLIENT_URL to the napRedirectURL. (see B rowser

Redirect to iNAP if using iNAP and Unauthorized User section)

020 4/17/24 Julie Olson Updated the User Experience with FAMAuth/iNAP flow chart for iNAP 2.12 changes.

021 5/9/24 Julie Olson Updated with FAMAuth 2.9 changes.

022 6/3/23 Julie Olson Updated with INAP 2.13 changes. (Rebrand)

Overview

The FAMAuth (Fire and Aviation Management Authentication and Authorization) Portal shown in the figure below, authenticates government application users via USDA eAuthentication and non-government users via Login.gov. Also, SAML federation bridging with eAuthentication may also be used to authenticate other agencies such as DOI.

FAMAuth is used in this document as a reference to this application. FAMAuth is also sometimes referred to as IWFIRP

(Interagency Wildland Fire Incident Response Portal).

FAMAuth currently supports the authentication of web server applications only.

Client applications that integrate with FAMAuth use the OAuth 2.0 protocol to validate that a user has authenticated in

FAMAuth (either via eAuthentication or Login.gov). OAuth 2.0 is the industry standard protocol for delegated authorization in the modern web, which is supported by leading companies like Google, Facebook and Twitter. Client applications will first authorize with FAMAuth to ensure that the user is authenticated, and will then be provided an access token that can be used to return information about the user from FAMAuth. This guide is intended for developers so they can understand the workflow to be able to integrate a client application and work with the FAMAuth team to onboard a new client application to leverage the shared authentication services.

An optional component to consider when integrating with FAMAuth is FAMAuth Admin (formerly known as iNAP), which holds entitlements for users of Wildland Fire applications. Users can request access to applications and roles, that are then approved or denied by application representatives. The information captured is available to client applications that are integrated with FAMAuth. See Appendix B: User Experience with FAMAuth Admin for additional information.

FAMAuth Portal with eAuthentication, Login.gov and FAMAuth Admin

Get Started: Registering a Client Application

To have your application added to the FAMAuth portal and leverage the authentication service, please send a request to the FAMIT point of contact: Ryan Hunt – ryan.hunt2@usda.gov. Include the following information in the request:

• Short Name – Typically an acronym or abbreviation

• Long Name – Full name of the application

• Description – Brief description of the application

• Application URL – The URL for launching the application

• Agency – An agency abbreviation, such as FS

• Image (optional) – A thumbnail icon for the application

• Use FAMAuth Admin for application access and roles? – Yes or No

For example:

• Short Name: OIS QCTEST

• Long Name: Organization Information System

• Description: Unit identifier and organizational unit repository

• Application URL: https://ois-qt.nwcg.gov/ois/login

• Agency: FS

• Image:

• Use FAMAuth Admin for application access and roles? Yes

The FAMAuth team will use the information above to create a tile in the FAMAuth portal, and the following information will be sent to the application team:

• Client ID – example: OIS-QA1

• Client Secret – example: oissecret mailto:ryan.hunt2@usda.gov

• If using FAMAuth Admin o Application Abbreviation – example: OIS o Instance Abbreviation – example: TEST

Once the tile has been created, a FAM application developer may request to be set up/authorized to maintain the following properties using the FAMAuth UI.

• Short Name

• Long Name

• Description

• Application URL

• (Allowed) Redirect URLs

Below describes the flow after implementation is completed

(See the Implementation section for more details)

A user launches the FAMAuth portal in their browser using https://famauth-qa.wildfire.gov, selects an identity provider (Login.gov or eAuthentication) and authenticates.

Upon successful authentication a session is established for the user in the FAMAuth portal and the tiles for all applications integrated with FAMAuth are displayed.

FAMAuth Team

The user clicks on the application tile rendered by FAMAuth and the Client App issues the redirection to the FAMAuth authorization service, initiating the OAuth2 exchange.

https://famauth-qa.wildfire.gov/oauth/authorize?client_id=OIS-

TEST&redirect_uri=https://ois-qt.nwcg.gov/ois/login&response_type=code&state=28IHK4

Client Developer

FAMAuth verifies that the user has a session in the FAMAuth portal. If not, the user is redirected to the identity provider selection page where they must authenticate (using

Login.gov or eAuthentication). Upon validation of the user session (or authentication)

FAMAuth returns an authorization code to the Client App.

https://ois-qt.nwcg.gov/ois/login?code=FIHxR6&state=28IHK4

FAMAuth Team

The Client App uses its Basic Authorization credentials (Client_ID:Client_Secret) via a back channel, to POST and acquire an access token for a successfully authenticated user.

POST https://famauth-qa.wildfire.gov/oauth/token

HEADER:

Authorization: Basic YWNZ….

Accept: application/json

BODY:

grant_type: authorization_code redirect_uri: https://ois-qt.nwcg.gov/ois/login code: FIHxR6

Client Developer

FAMAuth validates the Client_ID, Client_Secret, and authorization code, and returns an access token to the Client App.

FAMAuth Team file:///C:/FAMIT-Auth-service_DOC/ https:/iwfirp-dev.nwcg.gov/oauth/token

The access token is submitted via a back channel GET to retrieve the user profile.

https://famauth-qa.wildfire.gov/me?access_token=<access token>

Optionally include the application and instance abbreviations (from FAMAuth Admin) that user is being authorized for.

https://famauth-qa.wildfire.gov/me?access_token=<access token>&application=OIS&instance=TEST

Client Developer

FAMAuth returns the user profile.

The example provided here is for a user that authenticated via eAuthentication, and the client application is using FAMAuth Admin for access and roles. See

Section 6 for other responses.

"name": "{

\"usdaeauthid\":\"28552012122402152053535\", \"usdafirstname\": \"JOHN\", \"usdalastname\":\"SMITH\", \"usdaemail\":\"john.smith@usda.gov\", \"samaccountname\":\"null\", \"approles\":\"OCIO_ENTVPN_FS-EMP^USDA_ICAMaaS-

Federation_Customer_NFC^OCIO_CHD-Remedy_Record^OCIO_AgLearn_User\", \"managername\":\"null\"}", "email": "john.smith@usda.gov", "sub": "28552012122402152053535", This portion of the response is included if using FAMAuth Admin.

"authorized": "true", "napRedirectURL": null, "napUserProfile": "{

\"firstName\":\"John\", \"middleName\":null, \"lastName\":\"Smith\", \"userName\":\"jsmith\", \"napIdentifier\":\"1088661\", \"eMail\":\"john.smith@usda.gov\", \"primaryAffiliation\":\"Contractor/Vendor\", \"seasonalFlag\":false, \"dunsNumber\":null, \"uei\":null, \"inapAdminFlag\":true, \"editProfileRedirectURL\":\"http://localhost/nap/oauth2/authorization/fama uth?redirect_uri=%2FNAP%2F%3FACTION%3DfamHome%26TARGETPAGE%3DeditProfile%26EMAIL%3D xxx%40usda.com\", \"identityProviders\":[{

\"identityProviderID\":\"28552012122402152053535\", \"identityProviderSystem\":\"EAUTH\", \"identityProviderEmail\":\"john.smith@usda.gov\"}], \"applicationRoles\":[{

\"applicationRoleName\":\"Reference Data Administrator\", \"applicationRoleKey\":\"RDA\"}]}"

FAMAuth Team https://iwfirp-dev.nwcg.gov/me?access_token=%3caccess

If authorizing with FAMAuth Admin and authorized=false, redirect to the URL value provided in the napRedirectURL key.

This will display a page that will assist the user to do one or more of the following:

1. Request access [request a new user] or sign in with existing user

2. Edit their Profile and/or Request application access and roles

3. Accept Rules of Behavior

4. Receive instruction to restore their profile [if it has been removed]

5. Reactivate their user

Client Developer

USDA eAuthentication Integration Overview

For PIV authentication, FAMAuth is using the OAuth2 protocol to integrate with a client web application. The identity of a user is verified through the user accessing FAMAuth, acting as an authorization server. For eAuthentication, FAMAuth incorporates bridging of protocols to route the user to ICAM eAuthentication Identity Provider first, using the SAML

Passive Profile protocol, where the user is authenticated. The user is returned to FAMAuth with the SAML assertion.

The user invokes the client application next that acquires an authorization code. The client application will post the authorization code to FAMAuth for an access token, used to acquire the user profile.

The user initially logs into the FAMAuth portal using the flow in yellow invoking the eAuthentication option. Next, when the user clicks on an application link, the Client Web Application OAuth2 integration flow in the blue box takes place.

For additional information refer to Figure 1 below, detailing the FAMAuth Authentication Flow Diagram with SAML2

(eAuthication) and OAuth2 protocol chaining.

FAMAuth Authentication Service - Flow Diagram with

SAML2 (eAuthentication) and OAuth2 Protocol Chaining

Figure 1 SAML2 to OAuth2 Protocol Chaining

*For the Client Web Application OAuth2 handshake Implementation details (steps 1-6), refer below to the Web

Application Interface Description with OAuth2.

GSA Login.gov Integration Overview

For Login.gov authentication, FAMAuth is using the OAuth2 protocol to integrate with a client application (same as above). Instead of SAML Passing Profile in this case, FAMAuth will use OAuth2/OpenID connect to chain the two protocols together and authenticate the user with Login.gov. Once the user has been authenticated invoking FAMAuth first, the browser will be redirected back to the FAMAuth portal where the user can invoke an application tile to acquire an authorization code. The client application will post the authorization code to FAMAuth for an access token, used to acquire the user profile.

The user initially logs into the FAMAuth portal using the flow in yellow invoking the Login.gov option. Next, when the user clicks on an application tile (link), the Client Web Application OAuth2 integration flow in the blue box takes place.

The client application will post the authorization code to FAMAuth for an access token, submitted to acquire a user profile.

For additional information refer to Figure 2 below, detailing the FAMAuth Authentication Flow Diagram with

OAuth2/OpenID (Login.gov) and OAuth2 Protocol Chaining.

FAMAuth Authentication Service - Flow Diagram with

OAuth2/OpenID (Login.gov) and OAuth2 Protocol Chaining

Figure 2 OAuth2/OpenID to OAuth2 Protocol Chaining

* For the Client Web Application OAuth2 handshake Implementation details (steps 1-6), refer below to the Web

Application Interface Description with OAuth2.

Implementation: Login to the FAMAuth Portal

Part 1 - Authenticating with Service Provider (eAuthentication or Login.gov)

FAMAuth entails 2 parts. Part 1 is to login via eAuthentication or Login.gov from the Login Page. Upon successful authentication, the user is presented with the application page listing all available FAM Apps that have been added to

FAMAuth portal. Below details the steps to exectue Part 1 of the flow, no development required at this point to view listed applications on the FAMAuth portal.

The user has to log first into FAMAuth by invoking: https://famauth-qa.wildfire.gov (FAMAuth QA Server) and selecting the LOGIN.GOV or E-AUTHENTICATION cards.

Figure 3 - Login Page

The user is authenticated using the OAuth2\OpenID integration with LOGIN.GOV or SAML2 integration with eAuthentication. These exchanges are depicted in the flow diagram above in the yellow boxes. Upon successful authentication the FAMAuth portal is shown and the user’s email address from Login.gov or eAuthentication is displayed in the top right corner as shown below.

https://iwfirp-dev.nwcg.gov/

Figure 4 - Application Selection Page

Part 2 – Client Web Application Integration – 6 Steps

Part 2 applies only for applications that are listed on the FAMAuth portal. This flow is initiated upon clicking on the desired application access button associated with the application card. If you wish to add a new application to

FAMAuth, see Section Registering a Client App.

Upon application addition with FAMAuth, the developer will need to implement the 6 steps described below that correspond to Figure 2. (See sample code in Appendix if needed for example implementation)

To obtain the authorization server meta data use the URL: https://famauth-qa.wildfire.gov/meta or https://iwfirp.nwcg.gov/meta. This data will help with your OAuth2 client setup for calling FAMAuth.

Next, follow below steps 1 to 7 below, referring to their depicted corresponding steps in the flow diagram blue boxes.

STEP 1 – Invoke Client Application

The user invokes his client web application by clicking on one of the cards of the presented applications in the FAMAuth portal. This will call the URL provided by the developer during the application registration process.

STEP 2 – Browser Redirect to FAMAuth Authorization Server

At this stage the registered client application redirects the client browser to FAMAuth, which is acting as an OAuth2 authorization server.

Here is the GET (302 redirect request) that needs to be coded in the Client application, to redirect the user to the

FAMAuth authorization service:

https://famauth-qa.wildfire.gov/oauth/authorize?client_id=<my_client_id>& redirect_uri=https://<my_app_url>&response_type=code&state=<random_state>

Here is an actual GET (302 request) example.

https://famauth-qa.wildfire.gov/oauth/authorize?client_id=OIS-QA1&redirect_uri=https://ois-qt.nwcg.gov/ois/login_demo&response_type=code&state=28IHK4

The client application includes its client id, response_type (authorization code), local state (random state for preventing

CSRF) and a redirection URI to which FAMAuth will send the browser back once the user has been authenticated

(client_id and redirection URI are created during registration with FAMAuth).

STEP 3 – Authorization code returned from FAMAuth

If the user has been successfully authenticated via eAuthentication or Login.gov, FAMAuth responds to the client application with https://<Client Web App URL>?code=<authorization_code>&state=<random_state> containing the authorization code and the original state parameter. For example:

https://ois-qt.nwcg.gov/ois/login_demo?code=FIHxR6&state=28IHK4

No coding by the client application is required in Step 3.

STEP 4 – Authorization Code Posting for Acquiring Access Token

Upon obtaining the authorization code the client application code (need to be developed by the application team), posts in a backend channel the authorization code, redirect URI, client_id, client_secret to obtain an access_token for a successful response. The redirect URI sent to the token service must match the one that was sent to the authorize service.

POST authorization code https://famauth-qa.wildfire.gov/oauth/token?code=FIHxR6

The image below, Figure 5, depicts a Postman capture of a POST example

Figure 5 – Headers for TOKEN POST

Authorization: Basic YWNZ…. (Note: 'Basic '+ Base64 encoded ‘CLIENT_ID:CLIENT_SECRET’)

Accept: application/json

The image below, Figure 6, depicts the Postman capture of the POST example using query parameters, corresponding to the header above. Alternatively, these can be put in the body as form-data.

Figure 6 – Parameters for TOKEN POST grant_type: authorization_code redirect_uri: https://ois-qt.nwcg.gov/ois/login_demo code: cO_6vh

STEP 5 – The FAMAuth Response to Client Posting is an Access Token

The complete roundtrip of the POST example with the returned response is shown in Figure 7 below.

Figure 7 – Response for TOKEN POST

The response contains the following properties: {access_token, token_type, refresh_token, expires_in, scope, jti}.

“access_token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJPSVMtUUExIiwiaXNzIjoiaHR0cHM6Ly9pd2ZpcnAtcWEubn djZy5nb3YiLCJleHAiOjE2MzcyNzc2OTQsImp0aSI6IjQxMWQ5ZDQ2LWI4NmQtNDAwMy1iNDA5LTQ1MmExM2EzZDE2YSJ9.BMseiieoA1G2oGOuH x-Z1ry6pdw-f4gWGZWZsuQZSAh4EvG8Mgagtu6vBngTEPqhusWVnaRLeMxMuxrzrgr3jbmwvnrPvuQCK5DbNcIWZHk0dM3yldOffHTzMri5Ekt7NBFXZoOtaowL

824683xzxN_hB0bMqvTUyOKaVs2fUOi3inI9H60vsfOkBB2jd6g41TQf6K0YZ50TXMv9X9pIJqagAmVOkEs6XlD5N5rizNu2WthjIMROaxk1Pl8s

6B23yPdlJDB5HvXtw7HtQfSlwSu4rQQ2eQdzp2f2M4N_h8Weqf-Q31Z5Q8ByDaayXmTw5-w9TieVTqlQrLLeSH03Lg”, “token_type”: “bearer”, “refresh_token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJPSVMtUUExIiwiYXRpIjoiNDExZDlkNDYtYjg2ZC00MDAzL

WI0MDktNDUyYTEzYTNkMTZhIiwiaXNzIjoiaHR0cHM6Ly9pd2ZpcnAtcWEubndjZy5nb3YiLCJleHAiOjE2Mzk4NjYwOTQsImp0aSI6IjM4MzEyY

WM1LWYwY2QtNDk0ZC1iMWEyLTBhOGQ0ZTdmYTNkZCJ9.pcp7wc5Uu8QXVSdsuQny3U68QY0vZ_srsi5p5wiCWxkuga2QLDig9alahnHHAbAqrubA

HHmOO1kz5vOZ1wkHYnSuP6eYJ8C5LP68nuLMFO4zKHhU4ioIKXqK4Z74AYCa6iHee5Cv79hmmILPXfzNO1mVPw1inrV5kQS1bttxmXUhQUj4d5jk lkQr4Tani0t5R2VjyPFylAJ3AtRm4dGg-eQNhZD18TcvCukFgjG4HtnZEOBgefuQzFxar6Do8FknsBV0bKjwwT66QUtMOffFfoSURnsjceaslxCDAYpgRw44O-

KBMVBPW6cKn1rKNtoqHUyg_S6jbP6bn0NmzMAp1Q”, “expires_in”: 3599, “scope”: “read write”, “jti”: “411d9d46-b86d-4003-b409-452a13a3d16a”

The access_token property is a JWT comprised of a header, payload and signature that can be validated either by your application using https://famauth-qa.wildfire.gov/oauth/token_key to obtain the public key, or by having FAMAuth decode and validate it by calling https://famauth-qa.wildfire.gov/oauth/check_token?token=<access_token>.

STEP 6 - Issuing a GET with the Access Token for the authenticated user profile retrieval

To obtain information about the authenticated user the client application calls https://famauth-qa.wildfire.gov/me?access_token=<access_token>. If using iNAP additional parameters of application and instance should also be included to return access and roles from iNAP.

Figure 8 – GET User Information

The response contains the following properties: {name, email, sub, user_authenticated_by, authorized, napRedirectURL, napUserProfile}. Note that authorized, napRedirectURL and napUserProfile are only returned when the application and instance parameters are included.

Sample Response 1 - Response for eAuthentication and not using FAMAuth Admin:

"name": "{

\"usdaeauthid\":\"28552012122402152053535\", \"usdafirstname\": \"JOHN\", \"usdalastname\":\"SMITH\", \"usdaemail\":\"john.smith@usda.gov\", \"samaccountname\":\"null\", \"approles\":\"OCIO_ENTVPN_FS-EMP^USDA_ICAMaaS-Federation_Customer_NFC^OCIO_CHD-

Remedy_Record^OCIO_AgLearn_User\", \"managername\":\"null\"}", "email": "john.smith@usda.gov", "sub": "28552012122402152053535", "user_authenticated_by": "e-authentication"

Sample 2 - Response for Login.gov and not using FAMAuth Admin:

"name": "{

\"email\":\"john.smith@usda.gov\", \"uuid\":\"d789daf9-65b4-4c86-b6fc-5144d3eac3ac\"}", "email": "john.smith@acme.com", "sub": "d789daf9-65b4-4c86-b6fc-5144d3eac3ac", "user_authenticated_by": "login.gov"

Sample 3 - Authorized response for Login.gov and using FAMAuth Admin:

"name": "{

\"email\":\"john.smith@usda.gov\", \"uuid\":\"d789daf9-65b4-4c86-b6fc-5144d3eac3ac\"}", "email": "john.smith@acme.com", "sub": "d789daf9-65b4-4c86-b6fc-5144d3eac3ac", "user_authenticated_by": "login.gov ", "authorized": "true", "napRedirectURL": null, "napUserProfile": "{

\"firstName\":\"John\", \"middleName\":null, \"lastName\":\"Smith\", \"userName\":\"jsmith\", \"napIdentifier\":\"1088661\", \"eMail\":\"john.smith@acme.com\", \"primaryAffiliation\":\"Contractor/Vendor\", \"seasonalFlag\":false, \"dunsNumber\":null, \"uei\":null, \"inapAdminFlag\":true, \"editProfileRedirectURL\":\"http://localhost/nap/oauth2/authorization/famauth?redirect_uri=%2FNAP%2F%3F

ACTION%3DfamHome%26TARGETPAGE%3DeditProfile%26EMAIL%3Dxxx%40usda.com\", \"identityProviders\":[{

\"identityProviderID\":\" d789daf9-65b4-4c86-b6fc-5144d3eac3ac\", \"identityProviderSystem\":\"LOGIN.GOV\", \"identityProviderEmail\":\"john.smith@acme.com\"}], \"applicationRoles\":[{

\"applicationRoleName\":\"Reference Data Administrator\",\"applicationRoleKey\":\"RDA\"}, {\"applicationRoleName\":\"Unit ID Approver\",\"applicationRoleKey\":\"UIA\"}, {\"applicationRoleName\":\"Account Manager\",\"applicationRoleKey\":\"ACM\"}]}", Sample 4 - Unauthorized response for Login.gov and using FAMAuth Admin, where the client will need to redirect in the next step:

"name": "{

\"email\":\"john.smith@usda.gov\", \"uuid\":\"d789daf9-65b4-4c86-b6fc-5144d3eac3ac\"}", "email": "john.smith@acme.com", "sub": "d789daf9-65b4-4c86-b6fc-5144d3eac3ac", "user_authenticated_by": "login.gov ", "authorized": "false", "napRedirectURL": "https://nap-qt.nwcg.gov/NAP/?ACTION=login&IPID=d789daf9-65b4-4c86-b6fc-

5144d3eac3ac&IPSYSNAME=Login.gov&APP=OIS&INST=TEST&EMAIL=john.smith%40acme.com”, "napUserProfile": null", STEP 7 – Browser Redirect to FAMAuth Admin (if using FAMAuth Admin) and Unauthorized User

If the client application is using FAMAuth Admin and the response from the previous step contains authorized = false, then the client application will redirect the user to the URL provided in the napRedirectURL. This will display a page that will assist the user to do one or more of the following:

1. Request access [request a new user] or link an existing user

2. Edit their Profile and/or Request application access and roles

3. Accept Rules of Behavior

4. Receive instruction to restore their profile [if it has been removed]

5. Reactivate their user

If the client application would like FAMAuth Admin to redirect back to the client application for the client application to retry the OAUTH2 flows to get the napUserProfile after the user accepts rules of behavior for example, the client application can append the CLIENT_URL parameter to the napRedirectURL. Retrying the OAUTH2 flows could be different per implementation of the client application. The benefit of providing the CLIENT_URL is so that the end user is more likely to successfully authorize, without the disruption of having to “Return to FAMAuth to continue.” (to click the tile again). See Appendix B – User Experience with FAMAuth Admin Flow Diagram. The Optional redirect arrows (in red) illustrate the flows when CLIENT_URL is appended.

Appendix A: Web App Examples Integrating with the Authentication Service

A. Java Client App Sample Code, Authenticating Users with FAMAuth

The following sample of a Java Servlet code (client app SIT209), authenticates SIT209 users and can be used as a reference to integrate java based apps with FAMAuth.

- client_id=FAMsit209

- client_secret=XXS31w73

- redirect_uri=http://localhost:8080/fam-web-was/SIT209/login

- response_type=code

Note that the user will have to login via the FAMAuth portal first and invoke this client app code from the portal page.

The client web application redirects the browser (302) to FAMAuth (step 2).

FAMAuth sends the first response to the client app containing the "code" with a 302 redirection (step 3).

The client app matches the returned "state" to the one sent and proceeds to get the access token with the back channel

POST (step 4,5), followed by getting the user profile (step 6).

May refer to FAMAuth Service Flow Diagram with SAML2 Integration to eAuth and Client Web App Integration with

OAuth2; can follow with steps 1-6:

(Step 1) User invokes the client app.

(Step 2) https://famauth-qa.wildfire.gov/oauth/authorize?client_id=FAMsit209&redirect_uri=http://localhost:8080/fam-web-was/SIT209/login/login&response_type=code&state=28IHK4

(Step 3) http://localhost:8080/fam-web-was/SIT209/login?code= FIHxR6&state=28IHK4

(Step 4) POST https://famauth-qa.wildfire.gov/oauth/token

HEADER: Authorization: Basic YWNZ….

Accept: application/json

BODY: grant_type: authorization_code redirect_uri: http://localhost:8080/fam-web-was/SIT209/login/login code: FIHxR6

(Step 5) The access_token returning from the POST is comprised of the following properties:

{Access_token, token_type, refresh_token, expires_in, scope}.

private static class AuthResponse {

String access_token;

String token_type;

String refresh_token;

String expires_in;

String scope;

(Step 6) Issuing a GET with the access token for the authenticated user info retrieval.

https://famauth-qa.wildfire.gov/me?access_token

The sample code is comprised of the following classes:

package fam.security.oauth2.authentication.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import fam.security.oauth2.authentication.utils.OauthUtils;

public class GetTokenServlet extends HttpServlet { protected static final Logger logger = Logger.getLogger(GetTokenServlet.class);

public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try {

String code = req.getParameter(OauthUtils.CODE);

String returnedState = req.getParameter(OauthUtils.STATE);

String state = (String) ((HttpServletRequest) req).getSession()

.getAttribute(OauthUtils.STATE);

if (returnedState != null && state != null

&& state.equals(returnedState)) {

OauthUtils oauthUtils = new OauthUtils();

String token = oauthUtils.getAuthorizationToken(code);

String cred = oauthUtils.getUserCredentials(token);

String sessionUserId = oauthUtils.getSessionUserId(cred);

resp.addCookie(createCookie(sessionUserId));

resp.sendRedirect(OauthUtils.REDIRECT_HOME_PAGE);

} catch (Exception e) { e.printStackTrace();

throw new RuntimeException(e);

private Cookie createCookie(String sessionUserId) {

Cookie cookie = new Cookie(OauthUtils.CLIENT_COOKIE_NAME, sessionUserId);

cookie.setPath(OauthUtils.CLIENT_COOKIE_PATH);

cookie.setDomain(OauthUtils.CLIENT_COOKIE_DOMAIN);

return cookie;

This is the util class that does the heavy lifting. The first part is simply setting up the constants/values.

package fam.security.oauth2.authentication.utils;

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.net.URI;

import java.security.KeyManagementException;

import java.security.NoSuchAlgorithmException;

import java.util.ArrayList;

import java.util.List;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang.RandomStringUtils;

import org.apache.http.HttpEntity;

import org.apache.http.NameValuePair;

import org.apache.http.client.entity.EntityBuilder;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.client.utils.URIBuilder;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.conn.ssl.SSLContexts;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.params.BasicHttpParams;

import org.apache.http.params.HttpParams;

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

import org.codehaus.jackson.annotate.JsonProperty;

import org.codehaus.jackson.map.ObjectMapper;

import com.ibm.ws.util.Base64;

import fam.framework.exceptions.FAMDataException;

import fam.framework.util.FAMPropertyConfigurator;

import fam.security.oauth2.authentication.db.Oauth2DB;

* Examples of properties to be set:

fam.security.oauth2.client.cookie.path=/ fam.security.oauth2.client.cookie.domain=localhost fam.security.oauth2.url.client.redirect.home=http://localhost:8080/fam-web-was/SIT209/index.html fam.security.oauth2.url.protocol=https fam.security.oauth2.url.host=famauth-qa.wildfire.gov fam.security.oauth2.url.host.path.authorize=/oauth/authorize fam.security.oauth2.url.host.path.token=/oauth/token fam.security.oauth2.url.client.id=FAMsit209 fam.security.oauth2.url.client.redirectURI.token=http://localhost:8080/fam-web-was/SIT209/login fam.security.oauth2.url.responseType=code fam.security.oauth2.url.client.secret=XXS31w73

* @author Dan public class OauthUtils { public final static String CODE = "code";

public final static String STATE = "state";

public final static String OAUTH_REDIRECT_AUTHORIZE_URI;

public final static String CLIENT_COOKIE_PATH;

public final static String CLIENT_COOKIE_DOMAIN;

public final static String REDIRECT_HOME_PAGE;

public final static String STATE_PARM = "&state=";

public final static String CLIENT_COOKIE_NAME = "WSG_CLIENTID_COOKIE";

private final static String REDIRECT_URI = "redirect_uri";

private final static String ACCESS_TOKEN = "access_token";

private final static String CREDENTIALS_PATH = "/me";

private final static String GRANT_TYPE = "grant_type";

private final static String AUTHORIZATION_CODE = "authorization_code";

private final static String HEADER_ACCEPT = "Accept";

private final static String HEADER_ACCEPT_VALUE = "application/json";

private final static String HEADER_AUTHORIZATION = "Authorization";

private final static String HEADER_AUTHORIZATION_VALUE_BEARER = "bearer ";

private final static String PROTOCOL;

private final static String HOST;

private final static String CLIENT_ID_VALUE;

private final static String CLIENT_REDIRECT_URI_TOKEN_VALUE;

private final static String CLIENT_SECRET_VALUE;

private final static String OAUTH_SERVER_ACCESS_PATH_TOKEN;

private final static String HEADER_AUTHORIZATION_VALUE_BASIC;

private final static String RESPONSE_TYPE = "response_type";

private final static String CLIENT_ID = "client_id";

private final static String AND = "&";

private final static String EQ = "=";

private final static String QU = "?";

private final static String HOST_PATH_AUTHORIZE;

private final static String RESPONSE_TYPE_VALUE;

static {

FAMPropertyConfigurator.loadOverlays();

PROTOCOL = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.protocol");

HOST = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.host");

HOST_PATH_AUTHORIZE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.host.path.authorize");

CLIENT_ID_VALUE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.client.id");

CLIENT_REDIRECT_URI_TOKEN_VALUE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.client.redirectURI.token");

RESPONSE_TYPE_VALUE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.responseType");

CLIENT_SECRET_VALUE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.client.secret");

OAUTH_SERVER_ACCESS_PATH_TOKEN = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.host.path.token");

CLIENT_COOKIE_PATH = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.client.cookie.path");

CLIENT_COOKIE_DOMAIN = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.client.cookie.domain");

REDIRECT_HOME_PAGE = FAMPropertyConfigurator

.getRequiredProperty("fam.security.oauth2.url.client.redirect.home");

StringBuilder sb = new StringBuilder();

sb.append(PROTOCOL).append("://").append(HOST)

.append(HOST_PATH_AUTHORIZE).append(QU).append(CLIENT_ID)

.append(EQ).append(CLIENT_ID_VALUE).append(AND)

.append(REDIRECT_URI).append(EQ)

.append(CLIENT_REDIRECT_URI_TOKEN_VALUE).append(AND)

.append(RESPONSE_TYPE).append(EQ).append(RESPONSE_TYPE_VALUE);

OAUTH_REDIRECT_AUTHORIZE_URI = sb.toString();

HEADER_AUTHORIZATION_VALUE_BASIC = "Basic "

+ Base64.encode((CLIENT_ID_VALUE + ":" + CLIENT_SECRET_VALUE)

.getBytes());

public static String generateRandomState() { return RandomStringUtils.randomAlphanumeric(6);

public String getAuthorizationToken(String code) throws Exception {

List<NameValuePair> nameValuePairList = createNameValuePairList(code);

CloseableHttpResponse r = sendRequestPost(OauthUtils.HOST, OauthUtils.OAUTH_SERVER_ACCESS_PATH_TOKEN, nameValuePairList);

HttpEntity responseEntity = r.getEntity();

BufferedReader reader = new BufferedReader(new InputStreamReader( responseEntity.getContent()));

String line = new String();

line = reader.readLine();

responseEntity.consumeContent();

ObjectMapper mapper = new ObjectMapper();

AuthResponse atr = mapper.readValue(line, AuthResponse.class);

return atr.getAccess_token();

public String getUserCredentials(String token) throws Exception {

CloseableHttpResponse r = sendRequestGet(OauthUtils.HOST, OauthUtils.CREDENTIALS_PATH, token);

HttpEntity responseEntity = r.getEntity();

BufferedReader reader = new BufferedReader(new InputStreamReader( responseEntity.getContent()));

String line = new String();

line = reader.readLine();

ObjectMapper mapper = new ObjectMapper();

AuthResponse atr = mapper.readValue(line, AuthResponse.class);

responseEntity.consumeContent();

return atr.getName();

public String getSessionUserId(String cred) throws Exception {

Oauth2DB admin = new Oauth2DB();

return admin.getSessionUserId(cred);

private List<NameValuePair> createNameValuePairList(String code) {

List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();

NameValuePair parm = new BasicNameValuePair(OauthUtils.GRANT_TYPE, OauthUtils.AUTHORIZATION_CODE);

nameValuePairList.add(parm);

parm = new BasicNameValuePair(OauthUtils.REDIRECT_URI, OauthUtils.CLIENT_REDIRECT_URI_TOKEN_VALUE);

nameValuePairList.add(parm);

parm = new BasicNameValuePair(OauthUtils.CODE, code);

nameValuePairList.add(parm);

return nameValuePairList;

private CloseableHttpResponse sendRequestPost(String host, String path, List<NameValuePair> nameValuePairList) throws Exception {

URIBuilder uriBuilder = new URIBuilder().setScheme(OauthUtils.PROTOCOL)

.setHost(host);

URI uri = uriBuilder.setPath(path).build();

CloseableHttpClient httpclient = HttpClients.createDefault();

HttpPost httpPost = new HttpPost(uri);

httpPost.addHeader(HEADER_ACCEPT, HEADER_ACCEPT_VALUE);

httpPost.addHeader(HEADER_AUTHORIZATION, HEADER_AUTHORIZATION_VALUE_BASIC);

EntityBuilder entityBuilder = EntityBuilder.create();

entityBuilder.setParameters(nameValuePairList);

HttpEntity entity = entityBuilder.build();

httpPost.setEntity(entity);

return httpclient.execute(httpPost);

private CloseableHttpResponse sendRequestGet(String host, String path, String token) throws Exception {

URIBuilder uriBuilder = new URIBuilder().setScheme(OauthUtils.PROTOCOL)

.setHost(host);

URI uri = uriBuilder.setPath(path).build();

CloseableHttpClient httpclient = getHttpClient();

HttpParams httpParameters = new BasicHttpParams();

httpParameters.setParameter(OauthUtils.ACCESS_TOKEN, token);

HttpGet httpGet = new HttpGet(uri);

httpGet.setParams(httpParameters);

httpGet.setHeader(OauthUtils.HEADER_AUTHORIZATION, OauthUtils.HEADER_AUTHORIZATION_VALUE_BEARER + token);

httpGet.setHeader(OauthUtils.HEADER_ACCEPT, OauthUtils.HEADER_ACCEPT_VALUE);

return httpclient.execute(httpGet);

private CloseableHttpClient getHttpClient() throws FAMDataException {

CloseableHttpClient httpClient = null;

SSLContext sslContext = null;

try { sslContext = SSLContexts.custom().useTLS().build();

} catch (KeyManagementException e) {

String exceptionMsg = "KeyManagementException getting HttpClient: "

+ e.getMessage();

throw new FAMDataException(exceptionMsg);

} catch (NoSuchAlgorithmException e) {

String exceptionMsg = "NoSuchAlgorithmException getting HttpClient: "

+ e.getMessage();

throw new FAMDataException(exceptionMsg);

SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

httpClient = HttpClients.custom()

.setSSLSocketFactory(sslConnectionSocketFactory).build();

return httpClient;

@JsonIgnoreProperties(ignoreUnknown = true) private static class AuthResponse {

String token_type;

String refresh_token;

String scope;

String organization;

String jti;

String name;

@JsonProperty("access_token") public String getAccess_token() { return access_token;

@JsonProperty("access_token") public void setAccess_token(String access_token) { this.access_token = access_token;

@JsonProperty("token_type") public String getToken_type() { return token_type;

@JsonProperty("token_type") public void setToken_type(String token_type) { this.token_type = token_type;

@JsonProperty("refresh_token") public String getRefresh_token() { return refresh_token;

@JsonProperty("refresh_token") public void setRefresh_token(String refresh_token) { this.refresh_token = refresh_token;

@JsonProperty("expires_in") public String getExpires_in() { return expires_in;

@JsonProperty("expires_in") public void setExpires_in(String expires_in) { this.expires_in = expires_in;

@JsonProperty("scope") public String getScope() { return scope;

@JsonProperty("scope") public void setScope(String scope) { this.scope = scope;

@JsonProperty("organization") public String getOrganization() { return organization;

@JsonProperty("organization") public void setOrganization(String organization) { this.organization = organization;

@JsonProperty("cojtide") public String getJti() { return jti;

@JsonProperty("jti") public void setJti(String jti) { this.jti = jti;

@JsonProperty("name") public String getName() { return name;

@JsonProperty("name") public void setName(String name) { this.name = name;

B. .NET Client App Sample Code, Authenticating Users with FAMAuth

The following sample of a .NET code (client app acmenet), authenticates acmenet users, can be used as a reference to integrate .net based apps with FAMAuth.

- client_id= acmenet

- client_secret= acmesecretnet

- redirect_uri= http://fsxrnsx0128.wrk.fs.usda.gov/acme2

- response_type=code

Note that the user will have to login via the FAMAuth portal first and invoke this client app code from the portal page.

The client web application redirects the browser (302) to FAMAuth (step 2).

FAMAuth sends the first response to the client app containing the "code" with a 302 redirection (step 3).

The client app matches the returned "state" to the one sent and proceeds to get the access token with the back channel

POST (step 4,5), followed by getting the user profile (step 6).

May refer to FAMAuth Service Flow Diagram with SAML2 Integration to eAuth and Client Web App Integration with

OAuth2; can follow with steps 1-6:

(Step 1) User invokes the client app.

(Step 2) https://famauth-qa.wildfire.gov/oauth/authorize?client_id=acmene&redirect_uri= http://fsxrnsx0128.wrk.fs.usda.gov/acme2&response_type=code&state=28IHK4

(Step 3) http://localhost:8080/fam-web-was/SIT209/login?code= FIHxR6&state=28IHK4

(Step 4) POST https://famauth-qa.wildfire.gov/oauth/token

HEADER: Authorization: Basic YWNZ….

Accept: application/json

BODY: grant_type: authorization_code redirect_uri: http://fsxrnsx0128.wrk.fs.usda.gov/acme2 code: FIHxR6

(Step 5) The access_token returning from the POST is comprised of the following properties:

{Access_token, token_type, refresh_token, expires_in, scope}.

private static class AuthResponse {

String token_type;

String refresh_token;

String scope;

(Step 6) Issuing a GET with the access token for the authenticated user info retrieval.

https://famauth-qa.wildfire.gov/me?access_token fswebClientCore/fswebClientCore/appsettings.json

"auth": {

"oauth_clientId": "acmenet", "oauth_clientSecret": "acmesecretnet", "auth_code": "", "auth_server": "https://famauth-qa.wildfire.gov/", "REDIRECT_URL": "http://fsxrnsx0128.wrk.fs.usda.gov/acme2"

"Logging": {

"LogLevel": {

"Default": "Warning"

"AllowedHosts": "*" https://iwfirp-dev.nwcg.gov/me?access_token https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore fswebClientCore/fswebClientCore/fswebClientCore.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>

<TargetFramework>netcoreapp2.1</TargetFramework>

</PropertyGroup>

<ItemGroup>

<Folder Include="wwwroot\" />

</ItemGroup>

<ItemGroup>

<PackageReference Include="Microsoft.AspNetCore.App" />

</ItemGroup>

</Project> fswebClientCore/fswebClientCore/fswebClientCore.csproj.user

<?xml version="1.0" encoding="utf-8"?>

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>

<NameOfLastUsedPublishProfile>FolderProfile</NameOfLastUsedPublishProfile>

</PropertyGroup>

</Project> https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore fswebClientCore/fswebClientCore/Program.cs using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore;

using Microsoft.AspNetCore.Hosting;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.Logging;

namespace fswebClientCore public class Program public static void Main(string[] args)

CreateWebHostBuilder(args).Build().Run();

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>

WebHost.CreateDefaultBuilder(args)

.UseStartup<Startup>();

fswebClientCore/fswebClientCore/Startup.cs using System;

using System.Collections.Generic;

https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Logging;

using Microsoft.Extensions.Options;

namespace fswebClientCore public class Startup public Startup(IConfiguration configuration)

Configuration = configuration;

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.

public void ConfigureServices(IServiceCollection services) services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

services.AddHttpClient();

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env) if (env.IsDevelopment()) app.UseDeveloperExceptionPage();

app.UseDeveloperExceptionPage();

// app.UseMvc();

app.UseMvc(routes => routes.MapRoute("default", "{controller=Login}/{action=Login}");

fswebClientCore/fswebClientCore/appsettings.Development.json

"Logging": {

"LogLevel": {

"Default": "Debug", "System": "Information", https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore

"Microsoft": "Information" fswebClientCore/Controllers/LoginController.cs using System;

using System.Collections.Generic;

using System.Collections.Specialized;

using System.Linq;

using System.Net;

using System.Net.Http;

using System.Net.Http.Headers;

using System.Text;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.Configuration;

using Newtonsoft.Json;

using Newtonsoft.Json.Linq;

namespace fswebClientCore.Controllers

//.NET POCO object to convert from JSON object public class FAMUserAuth

[JsonProperty("access_token")] public string AccessToken { get; set; }

[JsonProperty("token_type")] public string TokenType { get; set; }

[JsonProperty("refresh_token")] public string RefreshToken { get; set; }

[JsonProperty("expires_in")] public int ExpiresIn { get; set; }

[JsonProperty("scope")] public string Scope { get; set; }

//.NET POCO object to convert from JSON Error object public class FAMAuthError https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore https://code.fs.usda.gov/EAD/FS-Apps/tree/Sample_NET_Client/sample/dotNet/fswebClientCore/fswebClientCore/Controllers

[JsonProperty("error")] public string Error { get; set; }

[JsonProperty("error_description")] public string ErrorDescription { get; set; }

[Route("api/[controller]")]

[ApiController] public class LoginController : ControllerBase

//Declarations private readonly IConfiguration configuration;

private readonly IHttpClientFactory clientFactory;

static string CLIENT_ID = "";

static string CLIENT_SECRET = "";

static string REDIRECT_URL = "";

static string JWT_PRIVATE_KEY_PASSWORD = "";

static string JWT_PUBLIC_KEY_ID = "";

static string AUTH_CODE = "";

static string AUTH_SERVER = "";

//Contrsuctor public LoginController(IConfiguration configuration, IHttpClientFactory clientFactory) this.configuration = configuration;

this.clientFactory = clientFactory;

//Grabs the configuration values from the appsettings.json file

//Set your configuration in the appsettings.json file

CLIENT_ID = configuration.GetValue<string>("auth:oauth_clientId");

CLIENT_SECRET = configuration.GetValue<string>("auth:oauth_clientSecret");

AUTH_CODE = configuration.GetValue<string>("auth:auth_code");

AUTH_SERVER = configuration.GetValue<string>("auth:auth_server");

REDIRECT_URL = configuration.GetValue<string>("auth:REDIRECT_URL");

JWT_PRIVATE_KEY_PASSWORD =

configuration.GetValue<string>("auth:boxPrivateKeyPassword");

JWT_PUBLIC_KEY_ID = configuration.GetValue<string>("auth:boxPublicKeyId");

// GET api/values

// Starting place / call that FAMAuth calls when click on the button on webpage

// http://<server>/api/Login for this example

[HttpGet] public IActionResult Login()

//Creates a random State

Guid g = Guid.NewGuid();

string state = Convert.ToBase64String(g.ToByteArray());

state = state.Replace("=", "");

state = state.Replace("+", "");

//it has to be 6 characters state = state.Substring(0, 6);

var type = "code";

//Create the request

//client_id = Client ID that is provided by the FAMAuth team

//redirect_uri = URL used for callback after getting request

//response_type = type of response , right now it's only code

//state = session type like id but its only limit to 6 chars var request = string.Format("{0}/oauth/authorize?client_id={1}&redirect_uri={2}&response_type={3}&state

={4}", AUTH_SERVER, CLIENT_ID, REDIRECT_URL, type, state);

//Must called as a redirect , a HTTP GET will not work return Redirect(request);

//After sending the request , the callback URL will be called with the Code

[Route("SignInCallback")] public IActionResult SignInCallback()

// Retrieve code and state from query string var qs =

Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(Request.QueryString.ToString()) var code = qs.Where(q => q.Key == "code").FirstOrDefault().Value;

var state = qs.Where(q => q.Key == "state").FirstOrDefault().Value;

//64 Encodes the Clientid and ClientSecret provided by FAMAuth team in the format of

// <clientid> : <client Secret> as string string auth =

Convert.ToBase64String(Encoding.UTF8.GetBytes($"{CLIENT_ID}:{CLIENT_SECRET}"));

//POCO object decalartion

FAMUserAuth userAuth = null;

//Declaration for end output display

StringBuilder sb = new StringBuilder();

// Send POST to make token request

// Creates a WebClient using (var wb = new WebClient())

//Adds Http Headers to the POST

//Accept , Json as result

//Authorization , pass the base 64 encoded client id : client secret string wb.Headers.Add("Accept",…

This is the start of the file's text. The full file is on GovTribe.

File details come from the government source that posted it. Updated .