|docs
Start Trial

Developer

User OAuth Token via Code Grant

User OAuth Token via Code Grant

Warning

This flow is for server-side apps

A client_secret should be treated as a password and stored securely. It should never be stored in public code. If you're working on an a mobile app or in-browser app, please use the PKCE flow.

About User OAuth Tokens via Code Grant

Before proceeding you should register a PagerDuty App with Scoped OAuth or Classic User OAuth functionality to obtain the client_id, client_secret, and scopes.

PagerDuty supports OAuth 2.0’s Authorization Code Grant flow for third-party applications to obtain access tokens from PagerDuty and utilizes the following endpoints:

Authorization Endpointhttps://identity.pagerduty.com/oauth/authorize
Token Endpointhttps://identity.pagerduty.com/oauth/token

The following parameters will also be used in your requests or returned in the response:

ParameterDescriptionRequired for token requestRequired for authorization requestRequired for refresh
client_idAn identifier issued when the app is created
client_secretA secret issued when the app is created.
codeThe authorization code issued upon a successful authorization request.
grant_typeThe OAuth 2.0 grant type. Value must be set to authorization_code or refresh_token
redirect_uriRegistered with the app when OAuth 2.0 is added. PagerDuty will redirect here after a user grants or denies access to your app.
response_typeSpecifies the response type based on OAuth 2.0 flow. Value must be set to code.
scopeSpecifies the scope being requested, must match [or be a subset of] what is configured for the OAuth functionality. Should be either read or write for Classic User OAuth or a space separated set of scopes for Scoped OAuth.
access_tokenThe token you will use to access the API after successful authorization.
refresh_tokenThe token you will use to get a new access token after the current access token has expired.

Warning

Never send your client_secret as a query parameter or over a non-https connection.

Obtaining an Access Token

Send a GET request to authorization endpoint with query parameters set for client_id, redirect_uri and scope, as defined in the app, and response_type=code

GET https://identity.pagerduty.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code

Authorized Requests

If the user authorizes the app, PagerDuty will redirect to the specified URI with the code (authorization code) in the URL:

{REDIRECT_URI}?code={AUTHORIZATION_CODE}

Denied Requests

If the user denies authorization, PagerDuty will redirect to the specified URI with error and error_description parameters:

{REDIRECT_URI}?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.

Exchanging an Authorization Code

To exchange the authorization code for an access token, send a POST request to the token endpoint. The authorization code has a time to live of 30 seconds, and your POST request must be received within that time. The body of the request should include the following parameters: client_id, client_secret, redirect_uri, the code (authorization code) received from PagerDuty, and grant_type=authorization_code. The content type should be application/x-form-urlencoded.

curl -X POST https://identity.pagerduty.com/oauth/token \
  --header "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id={CLIENT_ID}" \
  -d "client_secret={CLIENT_SECRET}" \
  -d "redirect_uri={REDIRECT_URI}" \
  -d "code={CODE}"

The access token will be included in a JSON response. You may also want to take note of the id token and the refresh token:

{
  "client_info":"prefix_legacy_app",
  "id_token":"eyJraWQiOiIxNzg3MzQ1MDA4IiwieDV0IjoiX2Nxbk1aWlBBcEF0V3kyVm11T1Y4dUc5VHNvIiwiYWxnIjoiUlMyNTYifQ.eyJleHAiOjE2NjYxOTk2MDEsIm5iZiI6MTY2NjE5NjAwMSwianRpIjoiODM3ODE1YzAtZTVmMi00M2RhLWFiYWYtYTE0ZjdhYzQ3ODYxIiwiaXNzIjoiaHR0cHM6Ly9hcHAucGFnZXJkdXR5LmNvbS9nbG9iYWwvb2F1dGgvYW5vbnltb3VzIiwiYXVkIjpbImh0dHBzOi8vYXBpLnBhZ2VyZHV0eS5jb20iLCI4ZTkxNDZmZS02NjllLTRjNjctYmIzOC1kODJhODg5YjM2ZWYiXSwic3ViIjoiUElZS0RCTiIsImF1dGhfdGltZSI6MTY2NjE5NTk5NSwiaWF0IjoxNjY2MTk2MDAxLCJwdXJwb3NlIjoiaWQiLCJhdF9oYXNoIjoiNkVqM3dzQUpDa2RPLTVtOFNuU29oUSIsImFjciI6ImFjcjpodG1sLWZvcm06dW5pdGVkc3RhdGVzIiwiZGVsZWdhdGlvbl9pZCI6ImM5YzliYWU1LWVkNzktNDg2Ny04NDQ1LWRmY2FkYmMwMzdiNSIsInByb2R1Y3RfYWJpbGl0aWVzIjpbXSwiYWNjb3VudF9pZCI6IlBFNlJMUTQiLCJ1c2VyX2lkIjoiUElZS0RCTiIsImF6cCI6IjhlOTE0NmZlLTY2OWUtNGM2Ny1iYjM4LWQ4MmE4ODliMzZlZiIsImFtciI6ImFjcjpodG1sLWZvcm06dW5pdGVkc3RhdGVzIiwic3ViZG9tYWluIjoicGR0LWhhbm5lbGUiLCJyZWdpb24iOiJVbml0ZWRTdGF0ZXMiLCJzaWQiOiJLRHo5V2h0bndqWXFKRnEzIn0.qBr2vJG-BkO0zAovDjxSkaxrenqzZC5Mcpy8Li-J37hae44j68PeIEJxMaknNZ3tMOyVjsd8AknjBoW2OeOv6Zk3RQMJd2inXDR9lIkEEMMgZ6PHI_tv3sM-9O4NR9OS4iCUtFMXjv6Sc-Dq_snjaTBw6ZK7vSERYwn57xe99z9JsaDzuLRX3mYhxApEUphr8GSty3TfI-fH_WIbuQhDOa6z8nExcKQWpNX18OEhig9AY2B88P21oBtYR3CnfqcRVH5nIXjAlGvCo6bcPM8MSVAmxY0spDFRNqaKNnPx4WMW_PyU7UxdMEZsO1fDOkTkHaS15FyRCoz0qhk5E3cYkg",
  "token_type":"bearer",
  "access_token":"pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN",
  "refresh_token":"pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN",
  "scope":"openid write",
  "expires_in":864000
}

Note however, that our access tokens do expire after a defined period of time -- so you may want to make sure that you implement OAuth refresh to prevent users needing to re-authorize your app. See more information about token expiries at the bottom of this page.

For additional information about the user, account, and PagerDuty service region where your app is now authorized, you can look at cracking open our PagerDuty-signed ID token. For example, the aud field will help your integration with data residency and processing guarantees if you have customers located in Europe.

Sample Code

LanguaugeGitHub Repository
Javascript / Node.jspagerduty-oauth-sample-node
Python 3pagerduty-oauth-sample-python

Using an Access Token

Once obtained, access tokens can be used to make REST API requests on behalf of the user.

When making an API request, include the version of the API in the Accept header. Access tokens must also be sent in the request as part of the Authorization header along with the Bearer token type, using this format:

Authorization: Bearer pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN
Accept: application/vnd.pagerduty+json;version=2

Troubleshooting: API Call results in 403

This means that although the OAuth credentials are valid, the token does not have access to that particular resource. For example, if you have a token with the read scope and try to write to a resource, it will result in 403.

If you think you requested the correct scope and should have access to the resource, double check the scope field in the POST Token Endpoint response. If an invalid scope is requested, we currently do not return an error. Instead, we grant partial scopes which will only be the openid scope automatically attached to all tokens.

Valid Scopes:

  • Read access should request the read scope (case sensitive)
  • Read/Write should request the write scope (case sensitive)

Getting a new Access Token with a Refresh Token

As mentioned, all of our current access tokens have an expiration date defined, so, it would be to your benefit to implement OAuth refresh to prevent your users from logging in unnecessarily.

Exchanging the refresh token for the access token is similar to using an authorization code: send a POST request to the token endpoint, but using the refresh_token grant type instead.

The body of the request should include the following parameters: client_id, client_secret, the refresh_token previously received from PagerDuty, and grant_type=refresh_token. The content type should still be application/x-form-urlencoded.

curl -X POST https://identity.pagerduty.com/oauth/token \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=refresh_token" \
  --data-urlencode "client_id={CLIENT_ID}" \
  --data-urlencode "client_secret={CLIENT_SECRET}" \
  --data-urlencode "refresh_token=pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN"

A successful response will include a new access token and a new refresh token:

{
    "token_type": "bearer",
    "access_token": "pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN",
    "refresh_token": "pdus+_EXAMPLE_KEY_ID_EXAMPLE_TOKEN",
    "scope": "openid write",
    "expires_in": 864000
}