AWS Cognito External User Pool Identity Provider(OIDC)

0

Hey, I'm using Cognito App Client integration with external provider(Twitch)
User authentication works fine, but as code from auth server is consumed by Cognito, I'm not sure how should I send Twitch requests with token, which I'd normally get from twitch I Cognito wouldn't consume this code. I only have Cognito code, which I can use in https://{my-domain}/oauth2/token requests in exchange for Cognito tokens. request returns id_token, access_token and refresh_token, which decoded look like
id token

{
  "at_hash": "yTNkeTAqzqcXCYi3yLL2Pw",
  "sub": "3cfba641-4058-475f-9818-17291175fd31",
  "cognito:groups": [
    "us-east-1_xxxxxxxxxxxx"
  ],
  "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxxxxxxxx",
  "cognito:username": "xxxxxxxxxxxx",
  "preferred_username": "xxxxxxxxxxxx",
  "nonce": "SxxlipCDVbXbcXa1H7Uf9_nM0uOurAAObUVCyreBDDux99QoAngUoiGdE0me-0Zon6fEVLLTSqD4EN1Y6_lFm48MaoBaxyywZCQKOT70gfQEfkuhlsjImJd1ko3qH3QKdlmvWSPCUZoACPYNSgR364VPELyQTVMkRTCt9eYROag",
  "aud": "35l1cn53cnj9sv1ndu8u01amk0",
  "identities": [
    {
      "userId": "xxxxxxxxxxxx",
      "providerName": "xxxxxxxxxxxx",
      "providerType": "OIDC",
      "issuer": null,
      "primary": "true",
      "dateCreated": "1588191000072"
    }
  ],
  "token_use": "id",
  "auth_time": 1588191003,
  "exp": 1588194603,
  "iat": 1588191003
}

access token

{
  "sub": "3cfba641-4058-475f-9818-17291175fd31",
  "cognito:groups": [
    "us-east-1_xxxxxxxxxxxx"
  ],
  "token_use": "access",
  "scope": "aws.cognito.signin.user.admin phone openid profile email",
  "auth_time": 1588191003,
  "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxxxxxxxx",
  "exp": 1588194603,
  "iat": 1588191003,
  "version": 2,
  "jti": "55863213-c764-4b07-a386-a9c93d14e4b2",
  "client_id": "xxxxxxxxxxxx",
  "username": "xxxxxxxxxxxx"
}

How can I get user token to call Twitch API (for example GET https://api.twitch.tv/helix/users endpoint with authorized user's token)?

asked 4 years ago1435 views
5 Answers
0

All cognito does is "authentication" with identity provider you configured. After authentication successed, all authorization process is handled by cognito which mean access_token, id_token and refresh_token are used only within cognito boundary (endpoints), cannot be used to call identity provider endpoints, in your case twitch.

If you wish to call twitch's APIs, you have to obtain tokens by calling twitch's authorization server with appropriate grant_type (like client_credentials) and client_id and client_secret generated at twitch. Once you got tokens from twitch, you can call any twitch's APIs depended on scopes of your client_id.

However, if you just want only some basic info of user, such as email, name, user_id, you can configure cognito to map attributes from twitch's id_token to cognito user attributes during the authentication. You may have to put specificed twitch's oauth scopes, something like 'email', 'profile', in cognito identity provider configuration, and you may also ask for user permission/consent (So, keep in mind that this particular info you may or may not got from user). After attribute mapping was configured correctly and user authenticated succuess, you can retreive the mapping values from decoding jwt of cognito's id_token, or using cognito's access_token to call cognito's userinfo enpoint.

Cognito event triggers are interesting to look into. I'm not sure can it be used to intercept ID provider's access_token and store somewhere, like in database , for further use, or not.

rexfr
answered 4 years ago
0

I've already checked triggers, and none of them contain any useful data

PreSignUp_ExternalProvider

{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1_xxxxx",
    "userName": "xxxxxxxx",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "xxxxxxxxxxx"
    },
    "triggerSource": "PreSignUp_ExternalProvider",
    "request": {
        "userAttributes": {
            "cognito:email_alias": "",
            "cognito:phone_number_alias": "",
            "preferred_username": "xxxxxxxxxxx"
        },
        "validationData": {}
    },
    "response": {
        "autoConfirmUser": false,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    }
}

PostConfirmation_ConfirmSignUp

{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1_xxxxxxx",
    "userName": "xxxxxxxxxxx",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "xxxxxxxxxxxxx"
    },
    "triggerSource": "PostConfirmation_ConfirmSignUp",
    "request": {
        "userAttributes": {
            "sub": "703e51b8-a471-4233-8637-f51feb0414b1",
            "identities": "[{\"userId\":\"xxxxxxxxxxxxx\",\"providerName\":\"xxxxxxxxxxx\",\"providerType\":\"OIDC\",\"issuer\":null,\"primary\":true,\"dateCreated\":1588257310792}]",
            "cognito:user_status": "EXTERNAL_PROVIDER",
            "preferred_username": "xxxxxxxxxxx"
        }
    },
    "response": {}
}

TokenGeneration_HostedAuth

{
    "version": "1",
    "triggerSource": "TokenGeneration_HostedAuth",
    "region": "us-east-1",
    "userPoolId": "us-east-xxxxxxxxxxx",
    "userName": "xxxxxxxxxxxxx",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "xxxxxxxxx"
    },
    "request": {
        "userAttributes": {
            "sub": "ed1fca3c-8084-4ae5-a128-ac37e38c7ffd",
            "cognito:user_status": "EXTERNAL_PROVIDER",
            "identities": "[{\"userId\":\"xxxxxxxxx\",\"providerName\":\"xxxxxxxxxx\",\"providerType\":\"OIDC\",\"issuer\":null,\"primary\":true,\"dateCreated\":1588255540224}]",
            "preferred_username": "xxxxxxxxxxx"
        },
        "groupConfiguration": {
            "groupsToOverride": [
                "us-east-xxxxxxxxxx"
            ],
            "iamRolesToOverride": [],
            "preferredRole": null
        }
    },
    "response": {
        "claimsOverrideDetails": null
    }
}

This idea with mapping attributes sounds interesting, but Cognito doesn't says anything about mapping anything else than user claims, so I'm not sure how do I do it
I've already specified these twitch auth scopes and I see these on consent screen, but I don't see any of these right after that

Also I think you may get me wrong - I want to use users token to perform actions on his behalf (like get banned users etc)

Edited by: piekarski on Apr 30, 2020 7:45 AM

answered 4 years ago
0

I don't think you can do that with cognito. I don't know much about twitch, but I guess it's a kind of social network, right?
IMO, the best you can do is using OAuth implicit grant type to let users do something on his/her behalf on your application. It's like having a Facebook's share button and comment section on websites that's not the Facebook website itself. You don't deal with user's access token on the backend, let's your app client, Facebook's APIs, and Facebook's OAuth server done for you.
However, in your case, it depends on the twitch's APIs you need allow you to call through implicit grant type, or not?

rexfr
answered 4 years ago
0

CAUTION - Doing it incorrectly, you expose sensitive attributes to client.

You need to create 2 versions of attributes - custom and dev:custom, map oidc provider attributes to custom ones (looks like dev:custom aren't mappable), then in TokenGeneration_HostedAuth trigger you need to get these custom attributes, set dev:custom ones, then delete customs.

Seems like a tweak, but I don't see another way of doing it and keeping tokens safe.

Solution for that is to create custom attributes in your user pool, then map these attributes for identity provider. Looks something like:

'custom:refresh_token': refresh_token
'custom:id_token': id_token
'custom:access_token': access_token

Cloudformation template for that:

user pool

....
Schema: [
    {
        AttributeDataType: 'String',
        DeveloperOnlyAttribute: true,
        Mutable: true,
        Name: 'refresh_token',
        Required: false,
    },
    {
        AttributeDataType: 'String',
        DeveloperOnlyAttribute: true,
        Mutable: true,
        Name: 'access_token',
        Required: false,
    },
    {
        AttributeDataType: 'String',
        DeveloperOnlyAttribute: true,
        Mutable: true,
        Name: 'id_token',
        Required: false,
    },
    {
        AttributeDataType: 'String',
        Mutable: true,
        Name: 'refresh_token',
        Required: false,
    },
    {
        AttributeDataType: 'String',
        Mutable: true,
        Name: 'access_token',
        Required: false,
    },
    {
        AttributeDataType: 'String',
        Mutable: true,
        Name: 'id_token',
        Required: false,
    },
],
....

user pool identity provider

....
AttributeMapping: {
    'custom:refresh_token': 'refresh_token',
    'custom:access_token': 'access_token',
    'custom:id_token': 'id_token',
},
....
answered 4 years ago
0

Congrat. and thank you for sharing your solution :)

rexfr
answered 4 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions