aws / aws/aws-appsync-community

Do subscriptions actually work with OIDC?

Open
#152 5 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
HTML
Stars
507
Forks
37
PR merge metrics
No merged PRs in 30d

Description

I created a GraphQL schema:

```graphql
type Query {
messages: [Message!]! @aws_iam @aws_oidc
}

type Message @aws_iam @aws_oidc {
topic: ID
text: String!
}

input SendMessageInput {
topic: ID!
text: String!
}
type Mutation {
sendMessage(message: SendMessageInput!): Message
@aws_iam
}
type Subscription {
onSendMessage(topic: ID): Message @aws_subscribe(mutations: ["sendMessage"])
}

schema {
query: Query
mutation: Mutation
subscription: Subscription
}
```

The idea is that only the server can send messages by executing the `onSendMessage` mutation. I had this working fine with API keys and IAM, but in actual usage, I need to have users authenticated.

I configured AppSync to use Google for OIDC and configured everything to allow this at the Google side.

```js
const api = new appsync.GraphqlApi(this, "subscriptionApi", {
name: "subscriptionApi",
schema: appsync.Schema.fromAsset(
path.join(__dirname, "../graphql/schema.graphql")
),
authorizationConfig: {
defaultAuthorization: {
authorizationType: appsync.AuthorizationType.OIDC,
// Get from https://console.cloud.google.com/apis/api/cloudidentity.googleapis.com
openIdConnectConfig: {
oidcProvider: "https://accounts.google.com",
clientId:
"xxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
},
},
additionalAuthorizationModes: [
{ authorizationType: appsync.AuthorizationType.IAM },
],
},
xrayEnabled: true,
});
```

It looks like there's a bug in the AWS console that prevents subscriptions from working in there with OIDC. It silently fails but logs it in the console (that wasted a lot of time).

Screen Shot 2021-02-21 at 12 37 45

This error is also referenced here: https://stackoverflow.com/questions/62283062/how-can-i-authenticate-subscription-with-openid-connect-in-appsync

So I tried out a subscription with graphiql.app, modifying the headers to include my Google-issued JWT, unfortunately that doesn't support subscriptions in the way I expect, and just returned a web socket URL. This was interesting because it shows how it's really just using IOT with a presigned URL.

Screen Shot 2021-02-21 at 09 52 14

I wasted some time writing little test harness to access the websocket URL in the browser, but got:

```
WebSocket connection to 'wss://xxxxxxx failed: Error during WebSocket handshake: Unexpected response code: 426
```

So I abandoned that, and found `graphqurl` (https://github.com/hasura/graphqurl) and tried that out.

```shell
export GRAPHQL_ENDPOINT="https://xxxxxx.appsync-api.eu-west-2.amazonaws.com/graphql"
export GRAPHQL_AUTH_HEADER="Authorization: xxxxxxxxxxx"
npx graphqurl $GRAPHQL_ENDPOINT -H "$GRAPHQL_AUTH_HEADER" \
-q 'subscription MySubscription { onSendMessage { topic text } }' -i
```

This pops up an interactive GraphiQL which does support subscriptions, but I still get an error.

Screen Shot 2021-02-21 at 12 53 47

Screen Shot 2021-02-21 at 12 52 25

I could see from the metrics that the Lambda function that backs the subscription wasn't getting executed at all.

```
const onSendMessage = new lambdaNode.NodejsFunction(this, "onSendMessage", {
runtime: lambda.Runtime.NODEJS_12_X,
entry: path.join(
__dirname,
"../handlers/graphql/subscription/onSendMessage.ts"
),
handler: "handler",
memorySize: 1024,
tracing: lambda.Tracing.ACTIVE,
});

api.addLambdaDataSource("onSendMessageDS", onSendMessage).createResolver({
typeName: "Subscription",
fieldName: "onSendMessage",
});
```

So, after enabling detailed logs, I could see that the requests were coming in from the tool (localhost:4500) and being rejected.

```
8ef7f10a-47a9-4ee5-8ece-e3e9fdd72822 Request Headers: {sec-websocket-protocol=[graphql-ws], cloudfront-viewer-country=[GB], sec-websocket-extensions=[permessage-deflate; client_max_window_bits], origin=[http://localhost:4500], x-forwarded-port=[443], sec-websocket-version=[13], via=[1.1 ace508199bd84d41add2e7c3b2f8dada.cloudfront.net (CloudFront)], cloudfront-is-desktop-viewer=[true], host=[mabyg5omevh6ndymqjhrafc35a.appsync-api.eu-west-2.amazonaws.com], connection=[upgrade], sec-websocket-key=[xxxx], cache-control=[no-cache], accept-language=[en-US,en;q=0.9], x-forwarded-proto=[https], upgrade=[websocket], x-forwarded-for=[xxxx], pragma=[no-cache], cloudfront-is-smarttv-viewer=[false], x-amzn-trace-id=[Root=1-603258f7-367b56910492de020b69e80f], cloudfront-is-tablet-viewer=[false], cloudfront-forwarded-proto=[https], accept-encoding=[gzip, deflate, br], x-amz-cf-id=[BmSQVyr3ogCATYc8hXh66QAP1pntUvxbEqrZHIt4WQOahf4mdZC0xw==], user-agent=[Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36], cloudfront-is-mobile-viewer=[false]}
```

```
8ef7f10a-47a9-4ee5-8ece-e3e9fdd72822 Response Headers: {x-amzn-ErrorType=UnauthorizedException}
```

But... I can execute a query using OIDC just fine.

Screen Shot 2021-02-21 at 13 10 11

I tried adding @aws_oidc to the subscription just as a test, and it made no difference at all.

Are OIDC supported for subscriptions? I can't see what I'm missing.

Contributor guide

Open the contributing guide

Research direction

Start with graphql/schema.graphql and the CDK configuration for subscriptionApi, then compare the working OIDC query with the subscription WebSocket handshake. Reproduce the graphqurl request while reviewing the detailed AppSync logs and the onSendMessage resolver setup. Done means establishing whether OIDC subscriptions are supported and documenting the required configuration or a confirmed service defect.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, graphql, typescript
Domain
api, authentication, backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.