aws-appsync-community
aws-appsync-community copied to clipboard
Do subscriptions actually work with OIDC?
I created a GraphQL schema:
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.
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](https://user-images.githubusercontent.com/1029947/108625217-9c5d7980-7441-11eb-8993-4fdde26ea637.png)
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](https://user-images.githubusercontent.com/1029947/108625305-1c83df00-7442-11eb-9580-331d02d3ae53.png)
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.
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](https://user-images.githubusercontent.com/1029947/108625640-eba4a980-7443-11eb-99df-9cd01794fa9e.png)
![Screen Shot 2021-02-21 at 12 52 25](https://user-images.githubusercontent.com/1029947/108625596-a97b6800-7443-11eb-8397-5b91600b4b11.png)
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](https://user-images.githubusercontent.com/1029947/108626083-450dd800-7446-11eb-9e25-703bb2fac2b2.png)
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.
Sorry for the trouble. We have a bug right now where OIDC subscriptions do not work through the console. We will address this shortly.
Thanks for the response @jpignata - did you see the bit where I use graphqurl
to work with a subscription using OIDC and that didn't work either?
I understand that the AWS console doesn't currently work (and hasn't for at least 9 months), graphiql.app doesn't work either (probably because of a bug or missing feature in that), but from what I can see, graphqurl seems to be doing the right thing - sending the Authorization header to AppSync, but the connection is not established.
Based on that, I started to think that the problem was with the AWS side, hence the question - do AppSync subscriptions work with OIDC?
This documentation https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html#header-parameter-format-based-on-appsync-api-authorization-mode makes it look like it does, but I have to create custom websocket code rather than use a GraphQL library.
@jpignata Hi. I'm experiencing the same problem. Are there any solution?
I'm experiencing the same problem too with auth0 oidc integration. Everything work, except subscriptions.
@LuisMourao - If it helps, I decided not to use AppSync for my project because I ran into so many problems. I wrote up my experience at https://adrianhesketh.com/2021/02/22/setting-up-appsync-graphql-subscriptions-with-typescript-and-cdk/