Configuring OAuth 2 for user-based workflows

Authorize your users using the PKCE method. Use PKCE authorization for securing integrations, especially with mobile applications.

PKCE authorization flow

Using PKCE protects against man-in-the-middle attacks that intercept the response from the OAuth 2 client and hijack the redirect URL to get the access token.
  1. An end user connects to your application.
  2. Your application redirects the user to the Faspex login page, served by the Faspex authentication component.
  3. The user enters their credentials on the login page.
  4. Your application submits those credentials along with the code verifier (matching the code challenge stored on the registered OAuth 2 client) to the Faspex authentication component to retrieve a bearer token.
  5. As the now authenticated user interacts with your application, your application makes API calls to the Faspex resource server using the bearer token.
  6. The Faspex authorization component server authorizes and serves the API call based on the identity associated with the bearer token.

About this task

To configure OAuth 2 for your application:

Procedure

  1. Register a new API client for your web application using the Faspex UI.
    1. Log in through the UI as an admin user.
    2. Go to the admin app.
    3. Go to Configurations > API clients and click Create new.
    4. Enter a Name and any Redirect URIs your web application uses.

      A redirect URI, or reply URL, is the location where the Faspex API sends your users once the Faspex login page has successfully authorized and granted an authorization code. Faspex sends the code to the redirect URI, so the redirect URI should be the endpoint your web application uses to retrieve and store an access token for your users.

      A standard endpoint is https://server/token.

      Note: Faspex requires redirect URIs to use the HTTPS format. If you do not have valid certificates to use for your application while in development, you can use self-signed certificates.
    5. Click Save.
  2. Save the generated Client ID.
  3. Implement the redirect URI endpoint in your web application.

    Your mobile application must accept two parameters, code and state, and use the values of those parameters to request a token from the API server using the aspera/faspex/auth/token endpoint.

    The sample Ruby code below returns a valid bearer token for use in subsequent API calls:

    require "net/http"
    require "json"
    
    # Expect code and state from API call
    authorization_code = params["code"]
    state = params["state"]
    
    # Set variables from environment
    faspex_hostname = ENV["FASPEX_HOSTNAME"]
    faspex_client_id = ENV["FASPEX_CLIENT_ID"]
    app_redirect_uri = ENV["APP_REDIRECT_URI"]
    code_verifier = ENV["CODE_VERIFIER"]
    
    # Build token request header and payload
    body = {
      "client_id": ENV["FASPEX_CLIENT_ID"],
      "grant_type": "authorization_code",
      "code": authorization_code,
      "code_verifier": Base64.encode64(params["state"]), # In this example, we assume the verifier and the state are the same
      "redirect_uri": ENV["APP_REDIRECT_URI"],
      "state": state
    }
    # Make a GET request to /aspera/faspex/auth/token
    uri = URI("https://#{FASPEX_HOSTNAME}/aspera/faspex/auth/token")
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE # If using self-signed certs
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = body.to_json
    request.content_type = "application/json"
    response = http.request(request)
    # Get bearer token from the response
    JSON.parse(response.body)["access_token"]
  4. Test your authorization flow.
    1. Start your web application in HTTPS mode so that it can receive the authorization code and state at its /token endpoint:
      FASPEX_HOSTNAME=faspex_hostname FASPEX_CLIENT_ID=faspex_hostname APP_REDIRECT_URI=https://your_server/token puma -b 'ssl://localhost:8443?key=ssl_certificate_key&cert=ssl_certificate_crt'
    2. Request an authorization code by logging in to Faspex. Use the client ID and redirect ID from the registered API client to generate a login URL.
      The URL syntax is:
      GET https://server/aspera/faspex/auth/authorize?client_id=faspex_client_id&redirect_uri=redirect_uri&response_type=code&state=state&code_challenge=code_challenge&code_challenge_method=code_challenge_method"
      Parameter Definition Example
      client_id The ID of the API client you registered. 266c8e7b-8bcb-40c2-b605-078b46c39d2a
      redirect_uri The location where the Faspex API sends your users once the Faspex login page has successfully authorized and granted an authorization code. https://faspex5.example.com/token
      state Unique identifier used in the /auth/token request to prove to the API server the client requesting the bearer token is the same client that received the authorization code. 96339c21-7d10-4d79-8043-93e7ab4cbe52
      code_challenge

      The code challenge is a Base64-encoded SHA256 hash of the code verifier. The code challenge is used for PKCE requests.

      ZWYyYmJlMmMtODA4MC00NWQ3LThiN2QtYTY1YmZjOGY5Mjkz\n (Code verifier: ef2bbe2c-8080-45d7-8b7d-a65bfc8f9293)
      code_challenge_method

      The code challenge method used to generate code challenge.

      s256
    3. After successful login, your application should provide you a valid bearer token. Use that token to retrieve your account information:
      Example curl command:
      curl "https://server/aspera/faspex/api/v5/account" \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer token"
      Example Ruby code:
      require "net/http"
      
      access_token = access_token
      uri = URI("https://#{ENV['FASPEX_HOST']}/aspera/faspex/api/v5/account")
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE # If using self-signed certs
      request = Net::HTTP::Get.new(uri.request_uri)
      request.content_type = "application/json"
      request["Authorization"] = "Bearer #{access_token}"
      http.request(request)