diff --git a/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js b/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js
index f0302c923999488e0bff14579e63e136db2ed916..cd1e92ece70b72b6194266ec6cc3ebfa4c365096 100644
--- a/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js
+++ b/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js
@@ -1,5 +1,10 @@
 import React from 'react'
-import { RadioGroup } from '@pubsweet/ui'
+import styled from 'styled-components'
+import { RadioGroup as UnstableRadioGroup } from '@pubsweet/ui'
+
+const RadioGroup = styled(UnstableRadioGroup)`
+  position: relative
+`
 
 const RadioboxFieldBuilder = input => <RadioGroup {...input} />
 export default RadioboxFieldBuilder
diff --git a/app/components/component-formbuilder/src/components/config/Elements.js b/app/components/component-formbuilder/src/components/config/Elements.js
index c46a8e7f2723809ba3fa773e1eb45b7725783dc3..1729f0c0bafcd83aea3c3380908c2b0c1a809188 100644
--- a/app/components/component-formbuilder/src/components/config/Elements.js
+++ b/app/components/component-formbuilder/src/components/config/Elements.js
@@ -147,6 +147,23 @@ const elements = {
         ],
       },
     },
+    DoiValidation: {
+      component: 'RadioBox',
+      props: {
+        inline: true,
+        options: [
+          {
+            value: 'true',
+            label: 'Yes',
+          },
+          {
+            value: 'false',
+            label: 'No',
+          },
+        ],
+        label: 'DOI Validation',
+      },
+    },
   },
   CheckboxGroup: {
     id: textfield,
diff --git a/app/components/component-submit/src/components/FormTemplate.js b/app/components/component-submit/src/components/FormTemplate.js
index 7a80fbf347d9bf5df18c44ba8d19e2c9149ce839..84e52cae8155ccbc98db368e85be9a3f6b8f3a35 100644
--- a/app/components/component-submit/src/components/FormTemplate.js
+++ b/app/components/component-submit/src/components/FormTemplate.js
@@ -19,6 +19,8 @@ import LinksInput from './LinksInput'
 import ValidatedFieldFormik from './ValidatedField'
 import Confirm from './Confirm'
 import { articleStatuses } from '../../../../globals'
+import { VALIDATE_DOI } from '../../../../queries/index'
+import { useApolloClient } from '@apollo/client'
 
 const Intro = styled.div`
   font-style: italic;
@@ -110,7 +112,7 @@ const createMarkup = encodedHtml => ({
   __html: unescape(encodedHtml),
 })
 
-const composeValidate = (vld = [], valueField = {}) => value => {
+const composeValidate = (vld = [], valueField = {}, fieldName, client) => value => {
   const validator = vld || []
 
   if (validator.length === 0) return undefined
@@ -129,6 +131,20 @@ const composeValidate = (vld = [], valueField = {}) => value => {
 
       return validatorFn
     })
+
+    if(errors.length === 0 && fieldName === 'submission.articleURL') {
+      return client.query({
+        query: VALIDATE_DOI, 
+        variables: {
+          articleURL: value
+        }
+      }).then(res => {
+        if (!res.data.validateDOI.isDOIValid) {
+          return 'DOI is invalid'
+        }
+        return undefined
+      })
+    }
   return errors.length > 0 ? errors[0] : undefined
 }
 
@@ -150,6 +166,7 @@ const FormTemplate = ({
   validateForm,
   match,
 }) => {
+  const client = useApolloClient()
   const submitButton = text => (
     <div>
       <Button
@@ -256,6 +273,8 @@ const FormTemplate = ({
                   validate={composeValidate(
                     element.validate,
                     element.validateValue,
+                    element.name,
+                    client
                   )}
                   values={values}
                 />
diff --git a/app/queries/index.js b/app/queries/index.js
index d4b8427653b96a29005d1b54cfa91eecef90ecaa..8b36453fbb992089937e1b520c04b4836217a40e 100644
--- a/app/queries/index.js
+++ b/app/queries/index.js
@@ -83,6 +83,18 @@ export const SEARCH_USERS = gql`
   }
 `
 
+export const VALIDATE_DOI = gql`
+  query Manuscripts(
+    $articleURL: String
+  ) {
+    validateDOI(
+      articleURL: $articleURL
+    ){
+      isDOIValid
+    }
+  }
+`
+
 export const GET_MANUSCRIPTS = gql`
   query Manuscripts(
     $sort: String
diff --git a/app/storage/forms-ncrc/submit.json b/app/storage/forms-ncrc/submit.json
index 5a0f0fcb2af05620377097cbfb3a34f3d1348153..cba65b43a009367cf62364c9fdc24bf1b12e3b1a 100644
--- a/app/storage/forms-ncrc/submit.json
+++ b/app/storage/forms-ncrc/submit.json
@@ -224,7 +224,7 @@
         ]
       }
     ],
-    "id": "NCRC Submission Form",
+    "id": "submit",
     "name": "NCRC Submission Form",
     "description": "<p>NCRC Form</p>",
     "haspopup": "false"
diff --git a/config/permissions.js b/config/permissions.js
index 27b697bc679d532c8984047d2fec2c72561ee768..a2c154abd0484ee6db92313f30a4a1722dfb5114 100644
--- a/config/permissions.js
+++ b/config/permissions.js
@@ -307,6 +307,7 @@ const permissions = {
     getForm: allow,
     getForms: allow,
     user: allow,
+    validateDOI: allow,
   },
   Mutation: {
     upload: isAuthenticated,
diff --git a/server/model-manuscript/src/graphql.js b/server/model-manuscript/src/graphql.js
index 2a1726f0144905bebb8ea9a2f236ff254594e5eb..7435cc6b387afa5fc4c5bf695cd154b6c8d12299 100644
--- a/server/model-manuscript/src/graphql.js
+++ b/server/model-manuscript/src/graphql.js
@@ -507,6 +507,23 @@ const resolvers = {
 
       // return ctx.connectors.User.fetchAll(where, ctx, { eager })
     },
+
+    async validateDOI(_, { articleURL }, ctx) {
+      const DOI = encodeURI(articleURL.split('.org/')[1])
+      try {
+        await axios.get(`https://api.crossref.org/works/${DOI}/agency`)
+
+        return {
+          isDOIValid: true
+        }
+      } catch(err) {
+        // eslint-disable-next-line
+        console.log(err)
+        return {
+          isDOIValid: false
+        }
+      }
+    }
   },
   // We want submission into to come out as a stringified JSON, so that we don't have to
   // change our queries if the submission form changes. We still want to store it as JSONB
@@ -522,6 +539,7 @@ const typeDefs = `
     manuscripts: [Manuscript]!
     paginatedManuscripts(sort: String, offset: Int, limit: Int, filter: ManuscriptsFilter): PaginatedManuscripts
     publishedManuscripts(sort:String, offset: Int, limit: Int): PaginatedManuscripts
+    validateDOI(articleURL: String): validateDOIResponse
   }
 
   input ManuscriptsFilter {
@@ -529,6 +547,10 @@ const typeDefs = `
     submission: String
   }
 
+  type validateDOIResponse {
+    isDOIValid: Boolean
+  }
+
   type PaginatedManuscripts {
     totalCount: Int
     manuscripts: [Manuscript]