aws / aws/aws-appsync-community
Do subscriptions actually work with OIDC?
- 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).

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.

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.


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.

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
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