Implementing secure API for use between other internal apps

Multi tool use
Multi tool use

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












My team and I are trying to implement a secure API and would appreciate some feedback on the following:



  • If there are areas of improvement in the current code to improve security


  • Recommendations on other secure API implementations, if any, that would fit our requirements better (see below)


  • If there are any major loopholes in security based on this module.


Here are some requirements, considerations, and caveats:



  • The API clients/consumers are other web apps from our same company (internal yet public facing apps on a different sub-domain)


  • We'd prefer not to go the OAuth2 route. We'd like this to be a programmatic interface using key-based authentication. Basically, it will be server to server authentication.


  • API is already https


We'd like this to be modular/flexible enough to use across different internal apps



Please read code comments. We've gotten inspiration from multiple sources, especially the implementation of JWT in a slightly different manner.



# Inspiration from:
# - https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
# - https://codeburst.io/jwt-to-authenticate-servers-apis-c6e179aa8c4e
# Typically, JWT's are used to provide consumer an access token after successful login.
# Considering our use case, the consumer (another internal app) will initiate the JWT
# Server will verify authenticity of request if it is able to decode JWT
# We've also set specific headers that internal apps would need to provide

module SecureAPI
# Generates a secure payload for outgoing requests
def self.secure_payload(options = , method = "get")
# Get or Post request
param_type = method == "get" ? "query" : "body"
iat = Time.now.to_i

# Reserved and Private claims
token_payload =
# The "iat" (issued at) claim identifies the time at which the JWT was issued.
iat: iat,
# Expiration
exp: iat + 60,
# Private claim
client_id: options[:client_id]


encoded_token = encode_token(token_payload, options[:shared_secret])

payload =
:headers =>
"Authorization" => "Bearer" + ' ' + encoded_token,
"JWT-Consumer" => options[:client_id]
,
param_type.to_sym =>
client_token: options[:client_token]


payload
end

# Verifies incoming requests/JWT verifier
def self.authenticate_request(request)
# Client must provide these headers
jwt_token = request.headers['Authorization'].split(' ').last

shared_secret = Rails.application.secrets[request.headers['JWT-Consumer']]

# Token must be decoded, unexpired, and verified using same hashing algo for successful auth
# else will return unauthorized response to client
decode_token(jwt_token, shared_secret)
end

def self.encode_token(payload, secret)
JWT.encode payload, secret, 'HS512'
end

def self.decode_token(token, shared_secret)
JWT.decode token, shared_secret, true, algorithm: 'HS512'
end
end








share|improve this question



























    up vote
    3
    down vote

    favorite












    My team and I are trying to implement a secure API and would appreciate some feedback on the following:



    • If there are areas of improvement in the current code to improve security


    • Recommendations on other secure API implementations, if any, that would fit our requirements better (see below)


    • If there are any major loopholes in security based on this module.


    Here are some requirements, considerations, and caveats:



    • The API clients/consumers are other web apps from our same company (internal yet public facing apps on a different sub-domain)


    • We'd prefer not to go the OAuth2 route. We'd like this to be a programmatic interface using key-based authentication. Basically, it will be server to server authentication.


    • API is already https


    We'd like this to be modular/flexible enough to use across different internal apps



    Please read code comments. We've gotten inspiration from multiple sources, especially the implementation of JWT in a slightly different manner.



    # Inspiration from:
    # - https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
    # - https://codeburst.io/jwt-to-authenticate-servers-apis-c6e179aa8c4e
    # Typically, JWT's are used to provide consumer an access token after successful login.
    # Considering our use case, the consumer (another internal app) will initiate the JWT
    # Server will verify authenticity of request if it is able to decode JWT
    # We've also set specific headers that internal apps would need to provide

    module SecureAPI
    # Generates a secure payload for outgoing requests
    def self.secure_payload(options = , method = "get")
    # Get or Post request
    param_type = method == "get" ? "query" : "body"
    iat = Time.now.to_i

    # Reserved and Private claims
    token_payload =
    # The "iat" (issued at) claim identifies the time at which the JWT was issued.
    iat: iat,
    # Expiration
    exp: iat + 60,
    # Private claim
    client_id: options[:client_id]


    encoded_token = encode_token(token_payload, options[:shared_secret])

    payload =
    :headers =>
    "Authorization" => "Bearer" + ' ' + encoded_token,
    "JWT-Consumer" => options[:client_id]
    ,
    param_type.to_sym =>
    client_token: options[:client_token]


    payload
    end

    # Verifies incoming requests/JWT verifier
    def self.authenticate_request(request)
    # Client must provide these headers
    jwt_token = request.headers['Authorization'].split(' ').last

    shared_secret = Rails.application.secrets[request.headers['JWT-Consumer']]

    # Token must be decoded, unexpired, and verified using same hashing algo for successful auth
    # else will return unauthorized response to client
    decode_token(jwt_token, shared_secret)
    end

    def self.encode_token(payload, secret)
    JWT.encode payload, secret, 'HS512'
    end

    def self.decode_token(token, shared_secret)
    JWT.decode token, shared_secret, true, algorithm: 'HS512'
    end
    end








    share|improve this question























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      My team and I are trying to implement a secure API and would appreciate some feedback on the following:



      • If there are areas of improvement in the current code to improve security


      • Recommendations on other secure API implementations, if any, that would fit our requirements better (see below)


      • If there are any major loopholes in security based on this module.


      Here are some requirements, considerations, and caveats:



      • The API clients/consumers are other web apps from our same company (internal yet public facing apps on a different sub-domain)


      • We'd prefer not to go the OAuth2 route. We'd like this to be a programmatic interface using key-based authentication. Basically, it will be server to server authentication.


      • API is already https


      We'd like this to be modular/flexible enough to use across different internal apps



      Please read code comments. We've gotten inspiration from multiple sources, especially the implementation of JWT in a slightly different manner.



      # Inspiration from:
      # - https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
      # - https://codeburst.io/jwt-to-authenticate-servers-apis-c6e179aa8c4e
      # Typically, JWT's are used to provide consumer an access token after successful login.
      # Considering our use case, the consumer (another internal app) will initiate the JWT
      # Server will verify authenticity of request if it is able to decode JWT
      # We've also set specific headers that internal apps would need to provide

      module SecureAPI
      # Generates a secure payload for outgoing requests
      def self.secure_payload(options = , method = "get")
      # Get or Post request
      param_type = method == "get" ? "query" : "body"
      iat = Time.now.to_i

      # Reserved and Private claims
      token_payload =
      # The "iat" (issued at) claim identifies the time at which the JWT was issued.
      iat: iat,
      # Expiration
      exp: iat + 60,
      # Private claim
      client_id: options[:client_id]


      encoded_token = encode_token(token_payload, options[:shared_secret])

      payload =
      :headers =>
      "Authorization" => "Bearer" + ' ' + encoded_token,
      "JWT-Consumer" => options[:client_id]
      ,
      param_type.to_sym =>
      client_token: options[:client_token]


      payload
      end

      # Verifies incoming requests/JWT verifier
      def self.authenticate_request(request)
      # Client must provide these headers
      jwt_token = request.headers['Authorization'].split(' ').last

      shared_secret = Rails.application.secrets[request.headers['JWT-Consumer']]

      # Token must be decoded, unexpired, and verified using same hashing algo for successful auth
      # else will return unauthorized response to client
      decode_token(jwt_token, shared_secret)
      end

      def self.encode_token(payload, secret)
      JWT.encode payload, secret, 'HS512'
      end

      def self.decode_token(token, shared_secret)
      JWT.decode token, shared_secret, true, algorithm: 'HS512'
      end
      end








      share|improve this question













      My team and I are trying to implement a secure API and would appreciate some feedback on the following:



      • If there are areas of improvement in the current code to improve security


      • Recommendations on other secure API implementations, if any, that would fit our requirements better (see below)


      • If there are any major loopholes in security based on this module.


      Here are some requirements, considerations, and caveats:



      • The API clients/consumers are other web apps from our same company (internal yet public facing apps on a different sub-domain)


      • We'd prefer not to go the OAuth2 route. We'd like this to be a programmatic interface using key-based authentication. Basically, it will be server to server authentication.


      • API is already https


      We'd like this to be modular/flexible enough to use across different internal apps



      Please read code comments. We've gotten inspiration from multiple sources, especially the implementation of JWT in a slightly different manner.



      # Inspiration from:
      # - https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
      # - https://codeburst.io/jwt-to-authenticate-servers-apis-c6e179aa8c4e
      # Typically, JWT's are used to provide consumer an access token after successful login.
      # Considering our use case, the consumer (another internal app) will initiate the JWT
      # Server will verify authenticity of request if it is able to decode JWT
      # We've also set specific headers that internal apps would need to provide

      module SecureAPI
      # Generates a secure payload for outgoing requests
      def self.secure_payload(options = , method = "get")
      # Get or Post request
      param_type = method == "get" ? "query" : "body"
      iat = Time.now.to_i

      # Reserved and Private claims
      token_payload =
      # The "iat" (issued at) claim identifies the time at which the JWT was issued.
      iat: iat,
      # Expiration
      exp: iat + 60,
      # Private claim
      client_id: options[:client_id]


      encoded_token = encode_token(token_payload, options[:shared_secret])

      payload =
      :headers =>
      "Authorization" => "Bearer" + ' ' + encoded_token,
      "JWT-Consumer" => options[:client_id]
      ,
      param_type.to_sym =>
      client_token: options[:client_token]


      payload
      end

      # Verifies incoming requests/JWT verifier
      def self.authenticate_request(request)
      # Client must provide these headers
      jwt_token = request.headers['Authorization'].split(' ').last

      shared_secret = Rails.application.secrets[request.headers['JWT-Consumer']]

      # Token must be decoded, unexpired, and verified using same hashing algo for successful auth
      # else will return unauthorized response to client
      decode_token(jwt_token, shared_secret)
      end

      def self.encode_token(payload, secret)
      JWT.encode payload, secret, 'HS512'
      end

      def self.decode_token(token, shared_secret)
      JWT.decode token, shared_secret, true, algorithm: 'HS512'
      end
      end










      share|improve this question












      share|improve this question




      share|improve this question








      edited Jun 26 at 5:58









      yuri

      3,3872832




      3,3872832









      asked Jun 26 at 4:08









      Katherine Eugenio

      161




      161

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197247%2fimplementing-secure-api-for-use-between-other-internal-apps%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197247%2fimplementing-secure-api-for-use-between-other-internal-apps%23new-answer', 'question_page');

          );

          Post as a guest













































































          kS,QY24ZNQebpLU5H,0futsfd9gjif0RO,eGYRNlV1D,nWqBMdt,kbHjN0 cwH48ota9LQA,E,hlxzh6EY0KM2eZS8dARu
          ayj8HC6 x2HEgLT363 dJtA0bDsyAkVAA4bGechx0x88NkJgzhpHdK

          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          ADO Stream Object