Search code examples
amazon-web-servicesstripe-paymentsauthorizationamazon-cognitoaws-amplify

Subscription based service with AWS, Stripe and React


I'm working on building a website with React for the Frontend, Stripe for payments, and AWS Services for the backend. I wanted to build a subscription based model. I'm using AWS Cognito for Authentication, DynamoDB for the Database, and GraphQL for the API calls from the Frontend. I've been trying to understand how to allow some of these GraphQL calls based only to users that are subsribed. I'm not sure how to put these things together

I read somewhere about customizing the access token with custom values. But I'm not sure if it's the best way for my case, what if a signed up user tries to make one of these API calls and it succeeds even though he isn't subscribed


Solution

  • There could be several ways to go about this. The most important aspect to remember is you will want to use the access token to determine any authorization decisions. Since you also mentioned the app involves payments, just keep security top of mind at all times and ensure you met whatever security posture is appropriate for your needs.

    One way for you to accomplish what you're trying to do (based solely on the information provided), is to use the groups in Amazon Cognito. As a very basic (and simple) example, you could have a "subscribedMembers" group in your Cognito user pool. If the user is a member of this group, the the issued access token after the user signs-in will contain a claim called cognito:groups and will display the group membership. Here's an example of what that claim would look like in the access token:

    "cognito:groups": [   
        "subscribedMembers"
    ],
    

    You could create a process within your application that would allow anyone to sign-up and create an account. This general step would simply create an account for user for your app. Then you could create a process that would allow a user to become a subscribed user of your app- aligning to whatever your requirements are for this. As a part of becoming a subscribed user, they would be added the "subscribedMembers" Cognito group. For example, the backend of your app could call the AdminAddUserToGroup API for this process.

    From the GraphQL perspective, let's assume you're using AWS AppSync, you could perform authorization decisions based on this group membership. As an example, you could have a request template that looked something like this:

    #foreach($group in $context.identity.claims.get("cognito:groups"))
        #if($group == "subscribedMembers")
            #set($inCognitoGroup = true)
        #end
    #end
    #if($inCognitoGroup)
    {
        "operation" : "GetData"
        // INSERT YOUR LOGIC HERE
    }
    #else
        $utils.unauthorized()
    #end
    

    A couple things to consider:

    • If using AppSync for your GraphQL API along with Amazon Cognito, the presented access token is validated as part of this process. If you're doing anything else with the access token (outside of AppSync) make sure to always verify and validate the access token first.
    • Since payments are invovled, I high highly consider always requiring MFA or even better take advantage of Cognito's advanced security features (aka ASF) to get features such as adaptive authentication and compromised credential check
    • Make sure you understand security best practices, particularly for securing the issued access tokens. OWASP has some great resources including how to mitigate issues related to Broken Access Control and Identification and Authentication Failures.
    • Speaking of the access tokens, consider issuing tokens that have the lowest TTL that aligns with you use case(s). For example, access tokens can be issued with expiration times between 5 minutes and 1 day. Note: if you using the hosted UI of Cognito, the minimum time would be brought up to 1 hour, as the hosted UI issues a 1 hr session-cookie.
    • The example, I gave above around using the group membership is valid and would work for very simple course-grain authorization uses cases. However, if you require more fine-grain authorization (think more dynamic in nature or authorization decision at runtime), then you should consider using Cognito's access token customization (part of ASF features) to modify the access token at time of creation or consider looking into using Amazon Verified Permissions (aka AVP).

    In addition to the above links, here's some additional resources to help: